diff --git a/CHANGELOG.md b/CHANGELOG.md index 051d9cd79cfe96b68df3f0163e858151e8e49ca6..af5c4acfbe0bab95847fb72694568dc5a50c6b2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] -*Nothing yet.* +### Removed + +* IPFS support has been removed due to maintenance burden. + +### Changed + +* Some admin endpoints for purging media, quarantining media, and background task information now require additional path components. See [docs/admin.md](./docs/admin.md) for more information. ## [1.2.13] - February 12, 2023 diff --git a/api/_apimeta/auth.go b/api/_apimeta/auth.go new file mode 100644 index 0000000000000000000000000000000000000000..943bbb18ed1059389eefd8b9f30a26cb02536a9b --- /dev/null +++ b/api/_apimeta/auth.go @@ -0,0 +1,29 @@ +package _apimeta + +import ( + "net/http" + + "github.com/getsentry/sentry-go" + + "github.com/turt2live/matrix-media-repo/common/rcontext" + "github.com/turt2live/matrix-media-repo/matrix" + "github.com/turt2live/matrix-media-repo/util" +) + +type UserInfo struct { + UserId string + AccessToken string + IsShared bool +} + +func GetRequestUserAdminStatus(r *http.Request, rctx rcontext.RequestContext, user UserInfo) (bool, bool) { + isGlobalAdmin := util.IsGlobalAdmin(user.UserId) || user.IsShared + isLocalAdmin, err := matrix.IsUserAdmin(rctx, r.Host, user.AccessToken, r.RemoteAddr) + if err != nil { + sentry.CaptureException(err) + rctx.Log.Error("Error verifying local admin: " + err.Error()) + return isGlobalAdmin, false + } + + return isGlobalAdmin, isLocalAdmin +} diff --git a/api/auth_cache/auth_cache.go b/api/_auth_cache/auth_cache.go similarity index 99% rename from api/auth_cache/auth_cache.go rename to api/_auth_cache/auth_cache.go index 69c0875db464742c76066fd3c38922eec38bba36..41756fb8eb1865c9b50dacbc33d93ef164665177 100644 --- a/api/auth_cache/auth_cache.go +++ b/api/_auth_cache/auth_cache.go @@ -1,4 +1,4 @@ -package auth_cache +package _auth_cache import ( "errors" diff --git a/api/_responses/content.go b/api/_responses/content.go new file mode 100644 index 0000000000000000000000000000000000000000..1f697ff00adf1509f670eea2717173095c51f74d --- /dev/null +++ b/api/_responses/content.go @@ -0,0 +1,21 @@ +package _responses + +import "io" + +type EmptyResponse struct{} + +type HtmlResponse struct { + HTML string +} + +type DownloadResponse struct { + ContentType string + Filename string + SizeBytes int64 + Data io.ReadCloser + TargetDisposition string +} + +type StreamDataResponse struct { + Stream io.Reader +} diff --git a/api/responses.go b/api/_responses/errors.go similarity index 91% rename from api/responses.go rename to api/_responses/errors.go index 93d2c39cbf59adcfa907400da85f55247be35794..deb93b29af320d492c13bdeb4234769c9c02e938 100644 --- a/api/responses.go +++ b/api/_responses/errors.go @@ -1,17 +1,7 @@ -package api +package _responses import "github.com/turt2live/matrix-media-repo/common" -type EmptyResponse struct{} - -type DoNotCacheResponse struct { - Payload interface{} -} - -type HtmlResponse struct { - HTML string -} - type ErrorResponse struct { Code string `json:"errcode"` Message string `json:"error"` @@ -22,6 +12,10 @@ func InternalServerError(message string) *ErrorResponse { return &ErrorResponse{common.ErrCodeUnknown, message, common.ErrCodeUnknown} } +func BadGatewayError(message string) *ErrorResponse { + return &ErrorResponse{common.ErrCodeUnknown, message, common.ErrCodeUnknown} +} + func MethodNotAllowed() *ErrorResponse { return &ErrorResponse{common.ErrCodeUnknown, "Method Not Allowed", common.ErrCodeMethodNotAllowed} } diff --git a/api/_responses/meta.go b/api/_responses/meta.go new file mode 100644 index 0000000000000000000000000000000000000000..0971bd72c889af94ba46ccea03bd239e17fde1c6 --- /dev/null +++ b/api/_responses/meta.go @@ -0,0 +1,5 @@ +package _responses + +type DoNotCacheResponse struct { + Payload interface{} +} diff --git a/api/_routers/00-install-params.go b/api/_routers/00-install-params.go new file mode 100644 index 0000000000000000000000000000000000000000..47c48d9a2473913564e23c202b3b141a9ebe980f --- /dev/null +++ b/api/_routers/00-install-params.go @@ -0,0 +1,29 @@ +package _routers + +import ( + "errors" + "net/http" + "regexp" + + "github.com/julienschmidt/httprouter" +) + +func localCompile(expr string) *regexp.Regexp { + r, err := regexp.Compile(expr) + if err != nil { + panic(errors.New("error compiling expression: " + expr + " | " + err.Error())) + } + return r +} + +var ServerNameRegex = localCompile("[a-zA-Z0-9.:\\-_]+") + +//var NumericIdRegex = localCompile("[0-9]+") + +func GetParam(name string, r *http.Request) string { + p := httprouter.ParamsFromContext(r.Context()) + if p == nil { + return "" + } + return p.ByName(name) +} diff --git a/api/_routers/01-install_metadata.go b/api/_routers/01-install_metadata.go new file mode 100644 index 0000000000000000000000000000000000000000..2ab5b29b9d347ddebc2740399966cef5cc0615c1 --- /dev/null +++ b/api/_routers/01-install_metadata.go @@ -0,0 +1,100 @@ +package _routers + +import ( + "context" + "net/http" + "strconv" + + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/util" +) + +const requestIdCtxKey = "mmr.request_id" +const actionNameCtxKey = "mmr.action" +const shouldIgnoreHostCtxKey = "mmr.ignore_host" +const loggerCtxKey = "mmr.logger" + +type RequestCounter struct { + lastId uint64 +} + +func (c *RequestCounter) NextId() string { + strId := strconv.FormatUint(c.lastId, 10) + c.lastId = c.lastId + 1 + + return "REQ-" + strId +} + +type InstallMetadataRouter struct { + next http.Handler + ignoreHost bool + actionName string + counter *RequestCounter +} + +func NewInstallMetadataRouter(ignoreHost bool, actionName string, counter *RequestCounter, next http.Handler) *InstallMetadataRouter { + return &InstallMetadataRouter{ + next: next, + ignoreHost: ignoreHost, + actionName: actionName, + counter: counter, + } +} + +func (i *InstallMetadataRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) { + requestId := i.counter.NextId() + logger := logrus.WithFields(logrus.Fields{ + "method": r.Method, + "host": r.Host, + "resource": r.URL.Path, + "contentType": r.Header.Get("Content-Type"), + "contentLength": r.ContentLength, + "queryString": util.GetLogSafeQueryString(r), + "requestId": requestId, + "remoteAddr": r.RemoteAddr, + "userAgent": r.UserAgent(), + }) + + ctx := r.Context() + ctx = context.WithValue(ctx, requestIdCtxKey, requestId) + ctx = context.WithValue(ctx, actionNameCtxKey, i.actionName) + ctx = context.WithValue(ctx, shouldIgnoreHostCtxKey, i.ignoreHost) + ctx = context.WithValue(ctx, loggerCtxKey, logger) + r = r.WithContext(ctx) + + if i.next != nil { + i.next.ServeHTTP(w, r) + } +} + +func GetRequestId(r *http.Request) string { + x, ok := r.Context().Value(requestIdCtxKey).(string) + if !ok { + return "REQ-ID-UNKNOWN" + } + return x +} + +func GetActionName(r *http.Request) string { + x, ok := r.Context().Value(actionNameCtxKey).(string) + if !ok { + return "<UNKNOWN>" + } + return x +} + +func ShouldIgnoreHost(r *http.Request) bool { + x, ok := r.Context().Value(shouldIgnoreHostCtxKey).(bool) + if !ok { + return false + } + return x +} + +func GetLogger(r *http.Request) *logrus.Entry { + x, ok := r.Context().Value(loggerCtxKey).(*logrus.Entry) + if !ok { + return nil + } + return x +} diff --git a/api/_routers/02-install-headers.go b/api/_routers/02-install-headers.go new file mode 100644 index 0000000000000000000000000000000000000000..e0b13f3a71baa1821eafa0a8bd77596cc82b3852 --- /dev/null +++ b/api/_routers/02-install-headers.go @@ -0,0 +1,28 @@ +package _routers + +import ( + "net/http" +) + +type InstallHeadersRouter struct { + next http.Handler +} + +func NewInstallHeadersRouter(next http.Handler) *InstallHeadersRouter { + return &InstallHeadersRouter{next: next} +} + +func (i *InstallHeadersRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) { + headers := w.Header() + headers.Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization") + headers.Set("Access-Control-Allow-Origin", "*") + headers.Set("Content-Security-Policy", "sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; media-src 'self'; object-src 'self';") + headers.Set("Cross-Origin-Resource-Policy", "cross-origin") + headers.Set("X-Content-Security-Policy", "sandbox;") + headers.Set("X-Robots-Tag", "noindex, nofollow, noarchive, noimageindex") + headers.Set("Server", "matrix-media-repo") + + if i.next != nil { + i.next.ServeHTTP(w, r) + } +} diff --git a/api/_routers/03-host_detection.go b/api/_routers/03-host_detection.go new file mode 100644 index 0000000000000000000000000000000000000000..a5e2ffb5ee2c8c746619f7837b92760735bf9574 --- /dev/null +++ b/api/_routers/03-host_detection.go @@ -0,0 +1,95 @@ +package _routers + +import ( + "context" + "encoding/json" + "errors" + "net" + "net/http" + "strings" + + "github.com/getsentry/sentry-go" + "github.com/prometheus/client_golang/prometheus" + "github.com/sebest/xff" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/metrics" + "github.com/turt2live/matrix-media-repo/util" +) + +const domainConfigCtxKey = "mmr.domain_config" + +type HostRouter struct { + next http.Handler +} + +func NewHostRouter(next http.Handler) *HostRouter { + return &HostRouter{next: next} +} + +func (h *HostRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("X-Forwarded-Host") != "" && config.Get().General.UseForwardedHost { + r.Host = r.Header.Get("X-Forwarded-Host") + } + r.Host = strings.Split(r.Host, ":")[0] + + var raddr string + if config.Get().General.TrustAnyForward { + raddr = r.Header.Get("X-Forwarded-For") + } else { + raddr = xff.GetRemoteAddr(r) + } + if raddr == "" { + raddr = r.RemoteAddr + } + host, _, err := net.SplitHostPort(raddr) + if err != nil { + logrus.Error(err) + sentry.CaptureException(err) + host = raddr + } + r.RemoteAddr = host + + ignoreHost := ShouldIgnoreHost(r) + isOurs := ignoreHost || util.IsServerOurs(r.Host) + if !isOurs { + logger := GetLogger(r) + metrics.InvalidHttpRequests.With(prometheus.Labels{ + "action": GetActionName(r), + "method": r.Method, + }).Inc() + logger.Warn("The server name provided in the Host header is not configured, or the request was made directly to the media repo. Please specify a Host header and check your reverse proxy configuration. The request is being rejected.") + w.WriteHeader(http.StatusBadGateway) + if b, err := json.Marshal(_responses.BadGatewayError("Review server logs to continue")); err != nil { + panic(errors.New("error preparing BadGatewayError: " + err.Error())) + } else { + if _, err = w.Write(b); err != nil { + panic(errors.New("error sending BadGatewayError: " + err.Error())) + } + } + return // don't call next handler + } + + cfg := config.GetDomain(r.Host) + if ignoreHost { + dc := config.DomainConfigFrom(*config.Get()) + cfg = &dc + } + + ctx := r.Context() + ctx = context.WithValue(ctx, domainConfigCtxKey, cfg) + r = r.WithContext(ctx) + + if h.next != nil { + h.next.ServeHTTP(w, r) + } +} + +func GetDomainConfig(r *http.Request) *config.DomainRepoConfig { + x, ok := r.Context().Value(domainConfigCtxKey).(*config.DomainRepoConfig) + if !ok { + return nil + } + return x +} diff --git a/api/_routers/04-request-metrics.go b/api/_routers/04-request-metrics.go new file mode 100644 index 0000000000000000000000000000000000000000..911e84d630a0648d23eb3d8827ef021b0e9268a7 --- /dev/null +++ b/api/_routers/04-request-metrics.go @@ -0,0 +1,28 @@ +package _routers + +import ( + "net/http" + + "github.com/prometheus/client_golang/prometheus" + "github.com/turt2live/matrix-media-repo/metrics" +) + +type MetricsRequestRouter struct { + next http.Handler +} + +func NewMetricsRequestRouter(next http.Handler) *MetricsRequestRouter { + return &MetricsRequestRouter{next: next} +} + +func (m *MetricsRequestRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) { + metrics.HttpRequests.With(prometheus.Labels{ + "host": r.Host, + "action": GetActionName(r), + "method": r.Method, + }).Inc() + + if m.next != nil { + m.next.ServeHTTP(w, r) + } +} diff --git a/api/_routers/97-optional-access-token.go b/api/_routers/97-optional-access-token.go new file mode 100644 index 0000000000000000000000000000000000000000..517ab346cd6e1d3901e34296f1786c0c12661be8 --- /dev/null +++ b/api/_routers/97-optional-access-token.go @@ -0,0 +1,55 @@ +package _routers + +import ( + "net/http" + + "github.com/getsentry/sentry-go" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_auth_cache" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/common/rcontext" + "github.com/turt2live/matrix-media-repo/matrix" + "github.com/turt2live/matrix-media-repo/util" +) + +func OptionalAccessToken(generator GeneratorWithUserFn) GeneratorFn { + return func(r *http.Request, ctx rcontext.RequestContext) interface{} { + accessToken := util.GetAccessTokenFromRequest(r) + if accessToken == "" { + return generator(r, ctx, _apimeta.UserInfo{ + UserId: "", + AccessToken: "", + IsShared: false, + }) + } + if config.Get().SharedSecret.Enabled && accessToken == config.Get().SharedSecret.Token { + ctx = ctx.LogWithFields(logrus.Fields{"sharedSecretAuth": true}) + return generator(r, ctx, _apimeta.UserInfo{ + UserId: "@sharedsecret", + AccessToken: accessToken, + IsShared: true, + }) + } + appserviceUserId := util.GetAppserviceUserIdFromRequest(r) + userId, err := _auth_cache.GetUserId(ctx, accessToken, appserviceUserId) + if err != nil { + if err != matrix.ErrInvalidToken { + sentry.CaptureException(err) + ctx.Log.Error("Error verifying token: ", err) + return _responses.InternalServerError("unexpected error validating access token") + } + + ctx.Log.Warn("Failed to verify token (non-fatal): ", err) + userId = "" + } + + ctx = ctx.LogWithFields(logrus.Fields{"authUserId": userId}) + return generator(r, ctx, _apimeta.UserInfo{ + UserId: userId, + AccessToken: accessToken, + IsShared: false, + }) + } +} diff --git a/api/_routers/97-require-access-token.go b/api/_routers/97-require-access-token.go new file mode 100644 index 0000000000000000000000000000000000000000..8d4b1fecf3c1baa89603896c41734c3e15e7dd81 --- /dev/null +++ b/api/_routers/97-require-access-token.go @@ -0,0 +1,59 @@ +package _routers + +import ( + "net/http" + + "github.com/getsentry/sentry-go" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_auth_cache" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/common" + "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/common/rcontext" + "github.com/turt2live/matrix-media-repo/matrix" + "github.com/turt2live/matrix-media-repo/util" +) + +type GeneratorWithUserFn = func(r *http.Request, ctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} + +func RequireAccessToken(generator GeneratorWithUserFn) GeneratorFn { + return func(r *http.Request, ctx rcontext.RequestContext) interface{} { + accessToken := util.GetAccessTokenFromRequest(r) + if accessToken == "" { + return &_responses.ErrorResponse{ + Code: common.ErrCodeMissingToken, + Message: "no token provided (required)", + InternalCode: common.ErrCodeMissingToken, + } + } + if config.Get().SharedSecret.Enabled && accessToken == config.Get().SharedSecret.Token { + ctx = ctx.LogWithFields(logrus.Fields{"sharedSecretAuth": true}) + return generator(r, ctx, _apimeta.UserInfo{ + UserId: "@sharedsecret", + AccessToken: accessToken, + IsShared: true, + }) + } + appserviceUserId := util.GetAppserviceUserIdFromRequest(r) + userId, err := _auth_cache.GetUserId(ctx, accessToken, appserviceUserId) + if err != nil || userId == "" { + if err == matrix.ErrGuestToken { + return _responses.GuestAuthFailed() + } + if err != nil && err != matrix.ErrInvalidToken { + sentry.CaptureException(err) + ctx.Log.Error("Error verifying token: ", err) + return _responses.InternalServerError("unexpected error validating access token") + } + return _responses.AuthFailed() + } + + ctx = ctx.LogWithFields(logrus.Fields{"authUserId": userId}) + return generator(r, ctx, _apimeta.UserInfo{ + UserId: userId, + AccessToken: accessToken, + IsShared: false, + }) + } +} diff --git a/api/_routers/97-require-repo-admin.go b/api/_routers/97-require-repo-admin.go new file mode 100644 index 0000000000000000000000000000000000000000..a298c5a6690c6f3d1103fd3630460502c292801f --- /dev/null +++ b/api/_routers/97-require-repo-admin.go @@ -0,0 +1,27 @@ +package _routers + +import ( + "errors" + "net/http" + + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/common/rcontext" + "github.com/turt2live/matrix-media-repo/util" +) + +func RequireRepoAdmin(generator GeneratorWithUserFn) GeneratorFn { + return func(r *http.Request, ctx rcontext.RequestContext) interface{} { + return RequireAccessToken(func(r *http.Request, ctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + if user.UserId == "" { + panic(errors.New("safety check failed: Repo admin access check received empty user ID")) + } + + if !util.IsGlobalAdmin(user.UserId) { + return _responses.AuthFailed() + } + + return generator(r, ctx, user) + }) + } +} diff --git a/api/_routers/98-use-rcontext.go b/api/_routers/98-use-rcontext.go new file mode 100644 index 0000000000000000000000000000000000000000..63fc7d06a5881826b3eda974d3579dad9d4040bc --- /dev/null +++ b/api/_routers/98-use-rcontext.go @@ -0,0 +1,305 @@ +package _routers + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "math" + "mime" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/alioygur/is" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/common" + "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/common/rcontext" + "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/stream_util" +) + +const statusCodeCtxKey = "mmr.status_code" + +type GeneratorFn = func(r *http.Request, ctx rcontext.RequestContext) interface{} + +type RContextRouter struct { + generatorFn GeneratorFn + next http.Handler +} + +func NewRContextRouter(generatorFn GeneratorFn, next http.Handler) *RContextRouter { + return &RContextRouter{generatorFn: generatorFn, next: next} +} + +func (c *RContextRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) { + log := GetLogger(r) + rctx := rcontext.RequestContext{ + Context: r.Context(), + Log: log, + Config: *GetDomainConfig(r), + Request: r, + } + + var res interface{} + res = c.generatorFn(r, rctx) + if res == nil { + res = &_responses.EmptyResponse{} + } + + shouldCache := true + wrappedRes, isNoCache := res.(*_responses.DoNotCacheResponse) + if isNoCache { + shouldCache = false + res = wrappedRes.Payload + } + + headers := w.Header() + + // Check for HTML response and reply accordingly + if htmlRes, isHtml := res.(*_responses.HtmlResponse); isHtml { + log.Infof("Replying with result: %T <%d chars of html>", res, len(htmlRes.HTML)) + + // Write out HTML here, now that we know it's happening + if shouldCache { + headers.Set("Cache-Control", "private, max-age=259200") // 3 days + } + headers.Set("Content-Type", "text/html; charset=UTF-8") + + // Clear the CSP because we're serving HTML + headers.Set("Content-Security-Policy", "") + headers.Set("X-Content-Security-Policy", "") + + r = writeStatusCode(w, r, http.StatusOK) + if _, err := w.Write([]byte(htmlRes.HTML)); err != nil { + panic(errors.New("error sending HtmlResponse: " + err.Error())) + } + return // don't continue + } + + // Next try handling the response as a download, which might turn into an error + proposedStatusCode := http.StatusOK + var stream io.ReadCloser + expectedBytes := int64(0) + var contentType string +beforeParseDownload: + log.Infof("Replying with result: %T %+v", res, res) + if downloadRes, isDownload := res.(*_responses.DownloadResponse); isDownload { + doRange, rangeStart, rangeEnd, grabBytes, rangeErrMsg := parseRange(r, downloadRes) + if doRange && rangeErrMsg != "" { + proposedStatusCode = http.StatusRequestedRangeNotSatisfiable + res = _responses.BadRequest(rangeErrMsg) + doRange = false + goto beforeParseDownload // reprocess `res` + } + + contentType = downloadRes.ContentType + expectedBytes = downloadRes.SizeBytes + + if shouldCache { + headers.Set("Cache-Control", "private, max-age=259200") // 3 days + } + + if downloadRes.SizeBytes > 0 { + if config.Get().Redis.Enabled { + headers.Set("Accept-Ranges", "bytes") + } + } + + disposition := downloadRes.TargetDisposition + if disposition == "" { + disposition = "inline" + } else if disposition == "infer" { + if contentType == "" { + disposition = "attachment" + } else { + if util.HasAnyPrefix(contentType, []string{"image/", "audio/", "video/", "text/plain"}) { + disposition = "inline" + } else { + disposition = "attachment" + } + } + } + fname := downloadRes.Filename + if fname == "" { + exts, err := mime.ExtensionsByType(contentType) + if err != nil { + exts = nil + sentry.CaptureException(err) + log.Warn("Unexpected error inferring file extension: ", err) + } + ext := "" + if exts != nil && len(exts) > 0 { + ext = exts[0] + } + fname = "file" + ext + } + if is.ASCII(fname) { + headers.Set("Content-Disposition", disposition+"; filename="+url.QueryEscape(fname)) + } else { + headers.Set("Content-Disposition", disposition+"; filename*=utf-8''"+url.QueryEscape(fname)) + } + + if doRange { + defer stream_util.DumpAndCloseStream(downloadRes.Data) + seekStream, err := stream_util.ManualSeekStream(downloadRes.Data, rangeStart, grabBytes) + if err != nil { + panic(err) // blow up the request + } + stream = io.NopCloser(seekStream) + expectedBytes = grabBytes + headers.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", rangeStart, rangeEnd, downloadRes.SizeBytes)) + proposedStatusCode = http.StatusPartialContent + } else { + stream = downloadRes.Data + } + } + + // Try to find a suitable error code, if one is needed + if errRes, isError := res.(*_responses.ErrorResponse); isError && proposedStatusCode == http.StatusOK { + switch errRes.InternalCode { + case common.ErrCodeUnknownToken: + proposedStatusCode = http.StatusUnauthorized + break + case common.ErrCodeNotFound: + proposedStatusCode = http.StatusNotFound + break + case common.ErrCodeMediaTooLarge: + proposedStatusCode = http.StatusRequestEntityTooLarge + break + case common.ErrCodeBadRequest: + proposedStatusCode = http.StatusBadRequest + break + case common.ErrCodeMethodNotAllowed: + proposedStatusCode = http.StatusMethodNotAllowed + break + case common.ErrCodeForbidden: + proposedStatusCode = http.StatusForbidden + break + default: // Treat as unknown (a generic server error) + proposedStatusCode = http.StatusInternalServerError + break + } + } + + // Prepare a stream if one isn't set, and assume JSON + if stream == nil { + contentType = "application/json" + b, err := json.Marshal(res) + if err != nil { + panic(err) // blow up this request + } + stream = io.NopCloser(bytes.NewReader(b)) + expectedBytes = int64(len(b)) + } + + mediaType, params, err := mime.ParseMediaType(contentType) + if err != nil { + sentry.CaptureException(err) + log.Warn("Failed to parse content type header for media on reply: ", err) + } else { + // TODO: Maybe we only strip the charset from images? Is it valid to have the param on other types? + if !strings.HasPrefix(mediaType, "text/") && mediaType != "application/json" { + delete(params, "charset") + } + contentType = mime.FormatMediaType(mediaType, params) + } + headers.Set("Content-Type", contentType) + + if expectedBytes > 0 { + headers.Set("Content-Length", strconv.FormatInt(expectedBytes, 10)) + } + + r = writeStatusCode(w, r, proposedStatusCode) + + defer stream_util.DumpAndCloseStream(stream) + written, err := io.Copy(w, stream) + if err != nil { + panic(err) // blow up this request + } + if expectedBytes > 0 && written != expectedBytes { + panic(errors.New(fmt.Sprintf("mismatch transfer size: %d expected, %d sent", expectedBytes, written))) + } + + if c.next != nil { + c.next.ServeHTTP(w, r) + } +} + +func GetStatusCode(r *http.Request) int { + x, ok := r.Context().Value(statusCodeCtxKey).(int) + if !ok { + return http.StatusOK + } + return x +} + +func writeStatusCode(w http.ResponseWriter, r *http.Request, statusCode int) *http.Request { + w.WriteHeader(statusCode) + return r.WithContext(context.WithValue(r.Context(), statusCodeCtxKey, statusCode)) +} + +func parseRange(r *http.Request, res *_responses.DownloadResponse) (bool, int64, int64, int64, string) { + rangeHeader := r.Header.Get("Range") + if rangeHeader == "" || res.SizeBytes <= 0 || !config.Get().Redis.Enabled { + return false, 0, 0, 0, "" + } + + if !strings.HasPrefix(rangeHeader, "bytes=") { + return true, 0, 0, 0, "Improper range units" + } + if !strings.Contains(rangeHeader, ",") && !strings.HasPrefix(rangeHeader, "bytes=-") { + parts := strings.Split(rangeHeader[len("bytes="):], "-") + if len(parts) <= 2 { + grabBytes := int64(0) + rstart, err := strconv.ParseInt(parts[0], 10, 64) + if err != nil { + return true, 0, 0, 0, "Improper start of range" + } + if rstart < 0 { + return true, 0, 0, 0, "Improper start of range: negative" + } + + rend := int64(-1) + if len(parts) > 1 && parts[1] != "" { + rend, err = strconv.ParseInt(parts[1], 10, 64) + if err != nil { + return true, 0, 0, 0, "Improper end of range" + } + if rend < 1 { + return true, 0, 0, 0, "Improper end of range: negative" + } + if rend >= res.SizeBytes { + return true, 0, 0, 0, "Improper end of range: out of bounds" + } + if rend <= rstart { + return true, 0, 0, 0, "Start must be before end" + } + if (rstart + rend) >= res.SizeBytes { + return true, 0, 0, 0, "Range too large" + } + + grabBytes = rend - rstart + } else { + add := int64(10485760) // 10mb default + conf := GetDomainConfig(r) + if conf.Downloads.DefaultRangeChunkSizeBytes > 0 { + add = conf.Downloads.DefaultRangeChunkSizeBytes + } + rend = int64(math.Min(float64(rstart+add), float64(res.SizeBytes-1))) + grabBytes = (rend - rstart) + 1 + } + + if (rend-rstart) <= 0 || grabBytes <= 0 { + return true, 0, 0, 0, "Range invalid at last pass" + } + return true, rstart, rend, grabBytes, "" + } + } + return false, 0, 0, 0, "" +} diff --git a/api/_routers/99-response-metrics.go b/api/_routers/99-response-metrics.go new file mode 100644 index 0000000000000000000000000000000000000000..8dd6eae2ea944553121328015188a215b4a0d870 --- /dev/null +++ b/api/_routers/99-response-metrics.go @@ -0,0 +1,30 @@ +package _routers + +import ( + "net/http" + "strconv" + + "github.com/prometheus/client_golang/prometheus" + "github.com/turt2live/matrix-media-repo/metrics" +) + +type MetricsResponseRouter struct { + next http.Handler +} + +func NewMetricsResponseRouter(next http.Handler) *MetricsResponseRouter { + return &MetricsResponseRouter{next: next} +} + +func (m *MetricsResponseRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) { + metrics.HttpResponses.With(prometheus.Labels{ + "host": r.Host, + "action": GetActionName(r), + "method": r.Method, + "statusCode": strconv.Itoa(GetStatusCode(r)), + }).Inc() + + if m.next != nil { + m.next.ServeHTTP(w, r) + } +} diff --git a/api/auth.go b/api/auth.go deleted file mode 100644 index 3cb51ef9d4a276f98a6e326a5a19722eb65f89cf..0000000000000000000000000000000000000000 --- a/api/auth.go +++ /dev/null @@ -1,127 +0,0 @@ -package api - -import ( - "github.com/getsentry/sentry-go" - "net/http" - - "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api/auth_cache" - "github.com/turt2live/matrix-media-repo/common" - "github.com/turt2live/matrix-media-repo/common/config" - "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/matrix" - "github.com/turt2live/matrix-media-repo/util" -) - -type UserInfo struct { - UserId string - AccessToken string - IsShared bool -} - -func callUserNext(next func(r *http.Request, rctx rcontext.RequestContext, user UserInfo) interface{}, r *http.Request, rctx rcontext.RequestContext, user UserInfo) interface{} { - r.WithContext(rctx) - return next(r, rctx, user) -} - -func AccessTokenRequiredRoute(next func(r *http.Request, rctx rcontext.RequestContext, user UserInfo) interface{}) func(*http.Request, rcontext.RequestContext) interface{} { - return func(r *http.Request, rctx rcontext.RequestContext) interface{} { - accessToken := util.GetAccessTokenFromRequest(r) - if accessToken == "" { - rctx.Log.Error("Error: no token provided (required)") - return &ErrorResponse{common.ErrCodeMissingToken, "no token provided (required)", common.ErrCodeUnknownToken} - } - if config.Get().SharedSecret.Enabled && accessToken == config.Get().SharedSecret.Token { - log := rctx.Log.WithFields(logrus.Fields{"isRepoAdmin": true}) - log.Info("User authed using shared secret") - return callUserNext(next, r, rctx, UserInfo{UserId: "@sharedsecret", AccessToken: accessToken, IsShared: true}) - } - appserviceUserId := util.GetAppserviceUserIdFromRequest(r) - userId, err := auth_cache.GetUserId(rctx, accessToken, appserviceUserId) - if err != nil || userId == "" { - if err == matrix.ErrGuestToken { - return GuestAuthFailed() - } - if err != nil && err != matrix.ErrInvalidToken { - sentry.CaptureException(err) - rctx.Log.Error("Error verifying token (fatal): ", err) - return InternalServerError("Unexpected Error") - } - - rctx.Log.Warn("Failed to verify token (fatal): ", err) - return AuthFailed() - } - - rctx = rctx.LogWithFields(logrus.Fields{"authUserId": userId}) - return callUserNext(next, r, rctx, UserInfo{userId, accessToken, false}) - } -} - -func AccessTokenOptionalRoute(next func(r *http.Request, rctx rcontext.RequestContext, user UserInfo) interface{}) func(*http.Request, rcontext.RequestContext) interface{} { - return func(r *http.Request, rctx rcontext.RequestContext) interface{} { - accessToken := util.GetAccessTokenFromRequest(r) - if accessToken == "" { - return callUserNext(next, r, rctx, UserInfo{"", "", false}) - } - if config.Get().SharedSecret.Enabled && accessToken == config.Get().SharedSecret.Token { - rctx = rctx.LogWithFields(logrus.Fields{"isRepoAdmin": true}) - rctx.Log.Info("User authed using shared secret") - return callUserNext(next, r, rctx, UserInfo{UserId: "@sharedsecret", AccessToken: accessToken, IsShared: true}) - } - appserviceUserId := util.GetAppserviceUserIdFromRequest(r) - userId, err := auth_cache.GetUserId(rctx, accessToken, appserviceUserId) - if err != nil { - if err != matrix.ErrInvalidToken { - rctx.Log.Error("Error verifying token: ", err) - return InternalServerError("Unexpected Error") - } - - rctx.Log.Warn("Failed to verify token (non-fatal): ", err) - userId = "" - } - - rctx = rctx.LogWithFields(logrus.Fields{"authUserId": userId}) - return callUserNext(next, r, rctx, UserInfo{userId, accessToken, false}) - } -} - -func RepoAdminRoute(next func(r *http.Request, rctx rcontext.RequestContext, user UserInfo) interface{}) func(*http.Request, rcontext.RequestContext) interface{} { - regularFunc := AccessTokenRequiredRoute(func(r *http.Request, rctx rcontext.RequestContext, user UserInfo) interface{} { - if user.UserId == "" { - rctx.Log.Warn("Could not identify user for this admin route") - return AuthFailed() - } - if !util.IsGlobalAdmin(user.UserId) { - rctx.Log.Warn("User " + user.UserId + " is not a repository administrator") - return AuthFailed() - } - - rctx = rctx.LogWithFields(logrus.Fields{"isRepoAdmin": true}) - return callUserNext(next, r, rctx, user) - }) - - return func(r *http.Request, rctx rcontext.RequestContext) interface{} { - if config.Get().SharedSecret.Enabled { - accessToken := util.GetAccessTokenFromRequest(r) - if accessToken == config.Get().SharedSecret.Token { - rctx = rctx.LogWithFields(logrus.Fields{"isRepoAdmin": true}) - rctx.Log.Info("User authed using shared secret") - return callUserNext(next, r, rctx, UserInfo{UserId: "@sharedsecret", AccessToken: accessToken, IsShared: true}) - } - } - - return regularFunc(r, rctx) - } -} - -func GetRequestUserAdminStatus(r *http.Request, rctx rcontext.RequestContext, user UserInfo) (bool, bool) { - isGlobalAdmin := util.IsGlobalAdmin(user.UserId) || user.IsShared - isLocalAdmin, err := matrix.IsUserAdmin(rctx, r.Host, user.AccessToken, r.RemoteAddr) - if err != nil { - sentry.CaptureException(err) - rctx.Log.Error("Error verifying local admin: " + err.Error()) - return isGlobalAdmin, false - } - - return isGlobalAdmin, isLocalAdmin -} diff --git a/api/custom/datastores.go b/api/custom/datastores.go index 75f60c0b3a686d2a0b59378527a1991436f9a2e9..93f3d23b9ecc738a742d3d217a65be481f7e9079 100644 --- a/api/custom/datastores.go +++ b/api/custom/datastores.go @@ -2,12 +2,14 @@ package custom import ( "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "net/http" "strconv" - "github.com/gorilla/mux" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/maintenance_controller" "github.com/turt2live/matrix-media-repo/storage" @@ -21,12 +23,12 @@ type DatastoreMigration struct { TaskID int `json:"task_id"` } -func GetDatastores(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func GetDatastores(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { datastores, err := storage.GetDatabase().GetMediaStore(rctx).GetAllDatastores() if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Error getting datastores") + return _responses.InternalServerError("Error getting datastores") } response := make(map[string]interface{}) @@ -38,24 +40,22 @@ func GetDatastores(r *http.Request, rctx rcontext.RequestContext, user api.UserI response[ds.DatastoreId] = dsMap } - return &api.DoNotCacheResponse{Payload: response} + return &_responses.DoNotCacheResponse{Payload: response} } -func MigrateBetweenDatastores(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func MigrateBetweenDatastores(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { beforeTsStr := r.URL.Query().Get("before_ts") beforeTs := util.NowMillis() var err error if beforeTsStr != "" { beforeTs, err = strconv.ParseInt(beforeTsStr, 10, 64) if err != nil { - return api.BadRequest("Error parsing before_ts: " + err.Error()) + return _responses.BadRequest("Error parsing before_ts: " + err.Error()) } } - params := mux.Vars(r) - - sourceDsId := params["sourceDsId"] - targetDsId := params["targetDsId"] + sourceDsId := _routers.GetParam("sourceDsId", r) + targetDsId := _routers.GetParam("targetDsId", r) rctx = rctx.LogWithFields(logrus.Fields{ "beforeTs": beforeTs, @@ -64,19 +64,19 @@ func MigrateBetweenDatastores(r *http.Request, rctx rcontext.RequestContext, use }) if sourceDsId == targetDsId { - return api.BadRequest("Source and target datastore cannot be the same") + return _responses.BadRequest("Source and target datastore cannot be the same") } sourceDatastore, err := datastore.LocateDatastore(rctx, sourceDsId) if err != nil { rctx.Log.Error(err) - return api.BadRequest("Error getting source datastore. Does it exist?") + return _responses.BadRequest("Error getting source datastore. Does it exist?") } targetDatastore, err := datastore.LocateDatastore(rctx, targetDsId) if err != nil { rctx.Log.Error(err) - return api.BadRequest("Error getting target datastore. Does it exist?") + return _responses.BadRequest("Error getting target datastore. Does it exist?") } rctx.Log.Info("User ", user.UserId, " has started a datastore media transfer") @@ -84,14 +84,14 @@ func MigrateBetweenDatastores(r *http.Request, rctx rcontext.RequestContext, use if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Unexpected error starting migration") + return _responses.InternalServerError("Unexpected error starting migration") } estimate, err := maintenance_controller.EstimateDatastoreSizeWithAge(beforeTs, sourceDsId, rctx) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Unexpected error getting storage estimate") + return _responses.InternalServerError("Unexpected error getting storage estimate") } migration := &DatastoreMigration{ @@ -99,23 +99,21 @@ func MigrateBetweenDatastores(r *http.Request, rctx rcontext.RequestContext, use TaskID: task.ID, } - return &api.DoNotCacheResponse{Payload: migration} + return &_responses.DoNotCacheResponse{Payload: migration} } -func GetDatastoreStorageEstimate(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func GetDatastoreStorageEstimate(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { beforeTsStr := r.URL.Query().Get("before_ts") beforeTs := util.NowMillis() var err error if beforeTsStr != "" { beforeTs, err = strconv.ParseInt(beforeTsStr, 10, 64) if err != nil { - return api.BadRequest("Error parsing before_ts: " + err.Error()) + return _responses.BadRequest("Error parsing before_ts: " + err.Error()) } } - params := mux.Vars(r) - - datastoreId := params["datastoreId"] + datastoreId := _routers.GetParam("datastoreId", r) rctx = rctx.LogWithFields(logrus.Fields{ "beforeTs": beforeTs, @@ -126,7 +124,7 @@ func GetDatastoreStorageEstimate(r *http.Request, rctx rcontext.RequestContext, if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Unexpected error getting storage estimate") + return _responses.InternalServerError("Unexpected error getting storage estimate") } - return &api.DoNotCacheResponse{Payload: result} + return &_responses.DoNotCacheResponse{Payload: result} } diff --git a/api/custom/exports.go b/api/custom/exports.go index dd79da759732deeafd62622ff620def4c945d070..f12439e94d433807676e23b53e31e5648e8eeb1c 100644 --- a/api/custom/exports.go +++ b/api/custom/exports.go @@ -2,14 +2,16 @@ package custom import ( "bytes" - "github.com/getsentry/sentry-go" "net/http" "strconv" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/dustin/go-humanize" - "github.com/gorilla/mux" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/api/r0" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/data_controller" @@ -36,25 +38,23 @@ type ExportMetadata struct { Parts []*ExportPartMetadata `json:"parts"` } -func ExportUserData(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func ExportUserData(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } isAdmin := util.IsGlobalAdmin(user.UserId) || user.IsShared if !rctx.Config.Archiving.SelfService && !isAdmin { - return api.AuthFailed() + return _responses.AuthFailed() } includeData := r.URL.Query().Get("include_data") != "false" s3urls := r.URL.Query().Get("s3_urls") != "false" - params := mux.Vars(r) - - userId := params["userId"] + userId := _routers.GetParam("userId", r) if !isAdmin && user.UserId != userId { - return api.BadRequest("cannot export data for another user") + return _responses.BadRequest("cannot export data for another user") } rctx = rctx.LogWithFields(logrus.Fields{ @@ -66,38 +66,36 @@ func ExportUserData(r *http.Request, rctx rcontext.RequestContext, user api.User if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("fatal error starting export") + return _responses.InternalServerError("fatal error starting export") } - return &api.DoNotCacheResponse{Payload: &ExportStarted{ + return &_responses.DoNotCacheResponse{Payload: &ExportStarted{ TaskID: task.ID, ExportID: exportId, }} } -func ExportServerData(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func ExportServerData(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } isAdmin := util.IsGlobalAdmin(user.UserId) || user.IsShared if !rctx.Config.Archiving.SelfService && !isAdmin { - return api.AuthFailed() + return _responses.AuthFailed() } includeData := r.URL.Query().Get("include_data") != "false" s3urls := r.URL.Query().Get("s3_urls") != "false" - params := mux.Vars(r) - - serverName := params["serverName"] + serverName := _routers.GetParam("serverName", r) if !isAdmin { // They might be a local admin, so check that. // We won't be able to check unless we know about the homeserver though if !util.IsServerOurs(serverName) { - return api.BadRequest("cannot export data for another server") + return _responses.BadRequest("cannot export data for another server") } isLocalAdmin, err := matrix.IsUserAdmin(rctx, serverName, user.AccessToken, r.RemoteAddr) @@ -106,7 +104,7 @@ func ExportServerData(r *http.Request, rctx rcontext.RequestContext, user api.Us isLocalAdmin = false } if !isLocalAdmin { - return api.BadRequest("cannot export data for another server") + return _responses.BadRequest("cannot export data for another server") } } @@ -119,23 +117,26 @@ func ExportServerData(r *http.Request, rctx rcontext.RequestContext, user api.Us if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("fatal error starting export") + return _responses.InternalServerError("fatal error starting export") } - return &api.DoNotCacheResponse{Payload: &ExportStarted{ + return &_responses.DoNotCacheResponse{Payload: &ExportStarted{ TaskID: task.ID, ExportID: exportId, }} } -func ViewExport(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func ViewExport(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } - params := mux.Vars(r) + exportId := _routers.GetParam("exportId", r) + + if !_routers.ServerNameRegex.MatchString(exportId) { + _responses.BadRequest("invalid export ID") + } - exportId := params["exportId"] rctx = rctx.LogWithFields(logrus.Fields{ "exportId": exportId, }) @@ -146,21 +147,21 @@ func ViewExport(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get metadata") + return _responses.InternalServerError("failed to get metadata") } parts, err := exportDb.GetExportParts(exportId) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get export parts") + return _responses.InternalServerError("failed to get export parts") } template, err := templating.GetTemplate("view_export") if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get template") + return _responses.InternalServerError("failed to get template") } model := &templating.ViewExportModel{ @@ -183,20 +184,23 @@ func ViewExport(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to render template") + return _responses.InternalServerError("failed to render template") } - return &api.HtmlResponse{HTML: string(html.Bytes())} + return &_responses.HtmlResponse{HTML: string(html.Bytes())} } -func GetExportMetadata(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func GetExportMetadata(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } - params := mux.Vars(r) + exportId := _routers.GetParam("exportId", r) + + if !_routers.ServerNameRegex.MatchString(exportId) { + _responses.BadRequest("invalid export ID") + } - exportId := params["exportId"] rctx = rctx.LogWithFields(logrus.Fields{ "exportId": exportId, }) @@ -207,14 +211,14 @@ func GetExportMetadata(r *http.Request, rctx rcontext.RequestContext, user api.U if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get metadata") + return _responses.InternalServerError("failed to get metadata") } parts, err := exportDb.GetExportParts(exportId) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get export parts") + return _responses.InternalServerError("failed to get export parts") } metadata := &ExportMetadata{ @@ -229,21 +233,25 @@ func GetExportMetadata(r *http.Request, rctx rcontext.RequestContext, user api.U }) } - return &api.DoNotCacheResponse{Payload: metadata} + return &_responses.DoNotCacheResponse{Payload: metadata} } -func DownloadExportPart(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func DownloadExportPart(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } - params := mux.Vars(r) + exportId := _routers.GetParam("exportId", r) + pid := _routers.GetParam("partId", r) - exportId := params["exportId"] - partId, err := strconv.ParseInt(params["partId"], 10, 64) + if !_routers.ServerNameRegex.MatchString(exportId) { + _responses.BadRequest("invalid export ID") + } + + partId, err := strconv.ParseInt(pid, 10, 64) if err != nil { rctx.Log.Error(err) - return api.BadRequest("invalid part index") + return _responses.BadRequest("invalid part index") } rctx = rctx.LogWithFields(logrus.Fields{ @@ -256,33 +264,35 @@ func DownloadExportPart(r *http.Request, rctx rcontext.RequestContext, user api. if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get part") + return _responses.InternalServerError("failed to get part") } s, err := datastore.DownloadStream(rctx, part.DatastoreID, part.Location) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to start download") + return _responses.InternalServerError("failed to start download") } return &r0.DownloadMediaResponse{ - ContentType: "application/gzip", - SizeBytes: part.SizeBytes, - Data: s, - Filename: part.FileName, + ContentType: "application/gzip", + SizeBytes: part.SizeBytes, + Data: s, + Filename: part.FileName, TargetDisposition: "attachment", } } -func DeleteExport(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func DeleteExport(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } - params := mux.Vars(r) + exportId := _routers.GetParam("exportId", r) - exportId := params["exportId"] + if !_routers.ServerNameRegex.MatchString(exportId) { + _responses.BadRequest("invalid export ID") + } rctx = rctx.LogWithFields(logrus.Fields{ "exportId": exportId, @@ -295,7 +305,7 @@ func DeleteExport(r *http.Request, rctx rcontext.RequestContext, user api.UserIn if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to delete export") + return _responses.InternalServerError("failed to delete export") } for _, part := range parts { @@ -304,7 +314,7 @@ func DeleteExport(r *http.Request, rctx rcontext.RequestContext, user api.UserIn if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to delete export") + return _responses.InternalServerError("failed to delete export") } rctx.Log.Info("Deleting object: " + part.Location) @@ -320,8 +330,8 @@ func DeleteExport(r *http.Request, rctx rcontext.RequestContext, user api.UserIn if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to delete export") + return _responses.InternalServerError("failed to delete export") } - return api.EmptyResponse{} + return _responses.EmptyResponse{} } diff --git a/api/custom/federation.go b/api/custom/federation.go index 4f50ee093a6eb1e8ebe7394b1038ad4ec570c5cd..84051d1388e075c9d2eefbc6bb581e4a175e81de 100644 --- a/api/custom/federation.go +++ b/api/custom/federation.go @@ -2,21 +2,25 @@ package custom import ( "encoding/json" - "github.com/getsentry/sentry-go" "io/ioutil" "net/http" - "github.com/gorilla/mux" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/matrix" ) -func GetFederationInfo(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) +func GetFederationInfo(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + serverName := _routers.GetParam("serverName", r) - serverName := params["serverName"] + if !_routers.ServerNameRegex.MatchString(serverName) { + return _responses.BadRequest("invalid server name") + } rctx = rctx.LogWithFields(logrus.Fields{ "serverName": serverName, @@ -26,7 +30,7 @@ func GetFederationInfo(r *http.Request, rctx rcontext.RequestContext, user api.U if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError(err.Error()) + return _responses.InternalServerError(err.Error()) } versionUrl := url + "/_matrix/federation/v1/version" @@ -34,14 +38,14 @@ func GetFederationInfo(r *http.Request, rctx rcontext.RequestContext, user api.U if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError(err.Error()) + return _responses.InternalServerError(err.Error()) } c, err := ioutil.ReadAll(versionResponse.Body) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError(err.Error()) + return _responses.InternalServerError(err.Error()) } out := make(map[string]interface{}) @@ -49,12 +53,12 @@ func GetFederationInfo(r *http.Request, rctx rcontext.RequestContext, user api.U if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError(err.Error()) + return _responses.InternalServerError(err.Error()) } resp := make(map[string]interface{}) resp["base_url"] = url resp["hostname"] = hostname resp["versions_response"] = out - return &api.DoNotCacheResponse{Payload: resp} + return &_responses.DoNotCacheResponse{Payload: resp} } diff --git a/api/custom/health.go b/api/custom/health.go index cab5bf9996372d36f74606209034d38c17904bc0..f890788bf562a6b70b92563b1e5c26d27fb27616 100644 --- a/api/custom/health.go +++ b/api/custom/health.go @@ -3,7 +3,8 @@ package custom import ( "net/http" - "github.com/turt2live/matrix-media-repo/api" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" "github.com/turt2live/matrix-media-repo/common/rcontext" ) @@ -12,8 +13,8 @@ type HealthzResponse struct { Status string `json:"status"` } -func GetHealthz(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - return &api.DoNotCacheResponse{ +func GetHealthz(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + return &_responses.DoNotCacheResponse{ Payload: &HealthzResponse{ OK: true, Status: "Probably not dead", diff --git a/api/custom/imports.go b/api/custom/imports.go index 3e51ef26e998d8ec70731aebafba982dbd7a3e67..532bd089dd03f00224ab5cf4159945a2d603c7bd 100644 --- a/api/custom/imports.go +++ b/api/custom/imports.go @@ -2,13 +2,15 @@ package custom import ( "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "net/http" - "github.com/gorilla/mux" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/data_controller" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) type ImportStarted struct { @@ -16,60 +18,64 @@ type ImportStarted struct { TaskID int `json:"task_id"` } -func StartImport(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func StartImport(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } - defer cleanup.DumpAndCloseStream(r.Body) + defer stream_util.DumpAndCloseStream(r.Body) task, importId, err := data_controller.StartImport(r.Body, rctx) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("fatal error starting import") + return _responses.InternalServerError("fatal error starting import") } - return &api.DoNotCacheResponse{Payload: &ImportStarted{ + return &_responses.DoNotCacheResponse{Payload: &ImportStarted{ TaskID: task.ID, ImportID: importId, }} } -func AppendToImport(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func AppendToImport(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } - params := mux.Vars(r) + importId := _routers.GetParam("importId", r) - importId := params["importId"] + if !_routers.ServerNameRegex.MatchString(importId) { + return _responses.BadRequest("invalid import ID") + } - defer cleanup.DumpAndCloseStream(r.Body) + defer stream_util.DumpAndCloseStream(r.Body) _, err := data_controller.AppendToImport(importId, r.Body, false) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("fatal error appending to import") + return _responses.InternalServerError("fatal error appending to import") } - return &api.DoNotCacheResponse{Payload: &api.EmptyResponse{}} + return &_responses.DoNotCacheResponse{Payload: &_responses.EmptyResponse{}} } -func StopImport(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func StopImport(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Archiving.Enabled { - return api.BadRequest("archiving is not enabled") + return _responses.BadRequest("archiving is not enabled") } - params := mux.Vars(r) + importId := _routers.GetParam("importId", r) - importId := params["importId"] + if !_routers.ServerNameRegex.MatchString(importId) { + return _responses.BadRequest("invalid import ID") + } err := data_controller.StopImport(importId) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("fatal error stopping import") + return _responses.InternalServerError("fatal error stopping import") } - return &api.DoNotCacheResponse{Payload: &api.EmptyResponse{}} + return &_responses.DoNotCacheResponse{Payload: &_responses.EmptyResponse{}} } diff --git a/api/custom/media_attributes.go b/api/custom/media_attributes.go index a4923330a57bd4de1891730d471a637bff94e255..b820ad167b3136551723781ce7626fb0acef4481 100644 --- a/api/custom/media_attributes.go +++ b/api/custom/media_attributes.go @@ -7,23 +7,24 @@ import ( "net/http" "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/turt2live/matrix-media-repo/util/stream_util" - "github.com/gorilla/mux" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/matrix" "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) type Attributes struct { Purpose string `json:"purpose"` } -func canChangeAttributes(rctx rcontext.RequestContext, r *http.Request, origin string, user api.UserInfo) bool { +func canChangeAttributes(rctx rcontext.RequestContext, r *http.Request, origin string, user _apimeta.UserInfo) bool { isGlobalAdmin := util.IsGlobalAdmin(user.UserId) || user.IsShared if isGlobalAdmin { return true @@ -36,11 +37,13 @@ func canChangeAttributes(rctx rcontext.RequestContext, r *http.Request, origin s return isLocalAdmin } -func GetAttributes(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) +func GetAttributes(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + origin := _routers.GetParam("server", r) + mediaId := _routers.GetParam("mediaId", r) - origin := params["server"] - mediaId := params["mediaId"] + if !_routers.ServerNameRegex.MatchString(origin) { + return _responses.BadRequest("invalid origin") + } rctx = rctx.LogWithFields(logrus.Fields{ "origin": origin, @@ -48,7 +51,7 @@ func GetAttributes(r *http.Request, rctx rcontext.RequestContext, user api.UserI }) if !canChangeAttributes(rctx, r, origin, user) { - return api.AuthFailed() + return _responses.AuthFailed() } // Check to see if the media exists @@ -57,10 +60,10 @@ func GetAttributes(r *http.Request, rctx rcontext.RequestContext, user api.UserI if err != nil && err != sql.ErrNoRows { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get media record") + return _responses.InternalServerError("failed to get media record") } if media == nil || err == sql.ErrNoRows { - return api.NotFoundError() + return _responses.NotFoundError() } db := storage.GetDatabase().GetMediaAttributesStore(rctx) @@ -69,19 +72,21 @@ func GetAttributes(r *http.Request, rctx rcontext.RequestContext, user api.UserI if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get attributes") + return _responses.InternalServerError("failed to get attributes") } - return &api.DoNotCacheResponse{Payload: &Attributes{ + return &_responses.DoNotCacheResponse{Payload: &Attributes{ Purpose: attrs.Purpose, }} } -func SetAttributes(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) +func SetAttributes(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + origin := _routers.GetParam("server", r) + mediaId := _routers.GetParam("mediaId", r) - origin := params["server"] - mediaId := params["mediaId"] + if !_routers.ServerNameRegex.MatchString(origin) { + return _responses.BadRequest("invalid origin") + } rctx = rctx.LogWithFields(logrus.Fields{ "origin": origin, @@ -89,15 +94,15 @@ func SetAttributes(r *http.Request, rctx rcontext.RequestContext, user api.UserI }) if !canChangeAttributes(rctx, r, origin, user) { - return api.AuthFailed() + return _responses.AuthFailed() } - defer cleanup.DumpAndCloseStream(r.Body) + defer stream_util.DumpAndCloseStream(r.Body) b, err := ioutil.ReadAll(r.Body) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to read attributes") + return _responses.InternalServerError("failed to read attributes") } newAttrs := &Attributes{} @@ -105,7 +110,7 @@ func SetAttributes(r *http.Request, rctx rcontext.RequestContext, user api.UserI if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to parse attributes") + return _responses.InternalServerError("failed to parse attributes") } db := storage.GetDatabase().GetMediaAttributesStore(rctx) @@ -114,20 +119,20 @@ func SetAttributes(r *http.Request, rctx rcontext.RequestContext, user api.UserI if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get attributes") + return _responses.InternalServerError("failed to get attributes") } if attrs.Purpose != newAttrs.Purpose { if !util.ArrayContains(types.AllPurposes, newAttrs.Purpose) { - return api.BadRequest("unknown purpose") + return _responses.BadRequest("unknown purpose") } err = db.UpsertPurpose(origin, mediaId, newAttrs.Purpose) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to update attributes: purpose") + return _responses.InternalServerError("failed to update attributes: purpose") } } - return &api.DoNotCacheResponse{Payload: newAttrs} + return &_responses.DoNotCacheResponse{Payload: newAttrs} } diff --git a/api/custom/purge.go b/api/custom/purge.go index e07523271c96534ac9ab2487d096a0b7a8e5d323..703cae8213a7b47945898a042b329a833f6a5212 100644 --- a/api/custom/purge.go +++ b/api/custom/purge.go @@ -2,13 +2,15 @@ package custom import ( "database/sql" - "github.com/getsentry/sentry-go" "net/http" "strconv" - "github.com/gorilla/mux" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/maintenance_controller" @@ -22,14 +24,14 @@ type MediaPurgedResponse struct { NumRemoved int `json:"total_removed"` } -func PurgeRemoteMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func PurgeRemoteMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { beforeTsStr := r.URL.Query().Get("before_ts") if beforeTsStr == "" { - return api.BadRequest("Missing before_ts argument") + return _responses.BadRequest("Missing before_ts argument") } beforeTs, err := strconv.ParseInt(beforeTsStr, 10, 64) if err != nil { - return api.BadRequest("Error parsing before_ts: " + err.Error()) + return _responses.BadRequest("Error parsing before_ts: " + err.Error()) } rctx = rctx.LogWithFields(logrus.Fields{ @@ -41,20 +43,22 @@ func PurgeRemoteMedia(r *http.Request, rctx rcontext.RequestContext, user api.Us if err != nil { rctx.Log.Error("Error purging remote media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Error purging remote media") + return _responses.InternalServerError("Error purging remote media") } - return &api.DoNotCacheResponse{Payload: &MediaPurgedResponse{NumRemoved: removed}} + return &_responses.DoNotCacheResponse{Payload: &MediaPurgedResponse{NumRemoved: removed}} } -func PurgeIndividualRecord(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - isGlobalAdmin, isLocalAdmin := api.GetRequestUserAdminStatus(r, rctx, user) +func PurgeIndividualRecord(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + isGlobalAdmin, isLocalAdmin := _apimeta.GetRequestUserAdminStatus(r, rctx, user) localServerName := r.Host - params := mux.Vars(r) + server := _routers.GetParam("server", r) + mediaId := _routers.GetParam("mediaId", r) - server := params["server"] - mediaId := params["mediaId"] + if !_routers.ServerNameRegex.MatchString(server) { + return _responses.BadRequest("invalid server ID") + } rctx = rctx.LogWithFields(logrus.Fields{ "server": server, @@ -64,41 +68,41 @@ func PurgeIndividualRecord(r *http.Request, rctx rcontext.RequestContext, user a // If the user is NOT a global admin, ensure they are speaking to the right server if !isGlobalAdmin { if server != localServerName { - return api.AuthFailed() + return _responses.AuthFailed() } // If the user is NOT a local admin, ensure they uploaded the content in the first place if !isLocalAdmin { db := storage.GetDatabase().GetMediaStore(rctx) m, err := db.Get(server, mediaId) if err == sql.ErrNoRows { - return api.NotFoundError() + return _responses.NotFoundError() } if err != nil { rctx.Log.Error("Error checking ownership of media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error checking media ownership") + return _responses.InternalServerError("error checking media ownership") } if m.UserId != user.UserId { - return api.AuthFailed() + return _responses.AuthFailed() } } } err := maintenance_controller.PurgeMedia(server, mediaId, rctx) if err == sql.ErrNoRows || err == common.ErrMediaNotFound { - return api.NotFoundError() + return _responses.NotFoundError() } if err != nil { rctx.Log.Error("Error purging media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error purging media") + return _responses.InternalServerError("error purging media") } - return &api.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true}} + return &_responses.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true}} } -func PurgeQuarantined(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - isGlobalAdmin, isLocalAdmin := api.GetRequestUserAdminStatus(r, rctx, user) +func PurgeQuarantined(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + isGlobalAdmin, isLocalAdmin := _apimeta.GetRequestUserAdminStatus(r, rctx, user) localServerName := r.Host var affected []*types.Media @@ -109,13 +113,13 @@ func PurgeQuarantined(r *http.Request, rctx rcontext.RequestContext, user api.Us } else if isLocalAdmin { affected, err = maintenance_controller.PurgeQuarantinedFor(localServerName, rctx) } else { - return api.AuthFailed() + return _responses.AuthFailed() } if err != nil { rctx.Log.Error("Error purging media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error purging media") + return _responses.InternalServerError("error purging media") } mxcs := make([]string, 0) @@ -123,17 +127,17 @@ func PurgeQuarantined(r *http.Request, rctx rcontext.RequestContext, user api.Us mxcs = append(mxcs, a.MxcUri()) } - return &api.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} + return &_responses.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} } -func PurgeOldMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func PurgeOldMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { var err error beforeTs := util.NowMillis() beforeTsStr := r.URL.Query().Get("before_ts") if beforeTsStr != "" { beforeTs, err = strconv.ParseInt(beforeTsStr, 10, 64) if err != nil { - return api.BadRequest("Error parsing before_ts: " + err.Error()) + return _responses.BadRequest("Error parsing before_ts: " + err.Error()) } } @@ -142,7 +146,7 @@ func PurgeOldMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI if includeLocalStr != "" { includeLocal, err = strconv.ParseBool(includeLocalStr) if err != nil { - return api.BadRequest("Error parsing include_local: " + err.Error()) + return _responses.BadRequest("Error parsing include_local: " + err.Error()) } } @@ -156,7 +160,7 @@ func PurgeOldMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI if err != nil { rctx.Log.Error("Error purging media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error purging media") + return _responses.InternalServerError("error purging media") } mxcs := make([]string, 0) @@ -164,13 +168,13 @@ func PurgeOldMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI mxcs = append(mxcs, a.MxcUri()) } - return &api.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} + return &_responses.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} } -func PurgeUserMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - isGlobalAdmin, isLocalAdmin := api.GetRequestUserAdminStatus(r, rctx, user) +func PurgeUserMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + isGlobalAdmin, isLocalAdmin := _apimeta.GetRequestUserAdminStatus(r, rctx, user) if !isGlobalAdmin && !isLocalAdmin { - return api.AuthFailed() + return _responses.AuthFailed() } var err error @@ -179,13 +183,11 @@ func PurgeUserMedia(r *http.Request, rctx rcontext.RequestContext, user api.User if beforeTsStr != "" { beforeTs, err = strconv.ParseInt(beforeTsStr, 10, 64) if err != nil { - return api.BadRequest("Error parsing before_ts: " + err.Error()) + return _responses.BadRequest("Error parsing before_ts: " + err.Error()) } } - params := mux.Vars(r) - - userId := params["userId"] + userId := _routers.GetParam("userId", r) rctx = rctx.LogWithFields(logrus.Fields{ "userId": userId, @@ -196,11 +198,11 @@ func PurgeUserMedia(r *http.Request, rctx rcontext.RequestContext, user api.User if err != nil { rctx.Log.Error("Error parsing user ID (" + userId + "): " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error parsing user ID") + return _responses.InternalServerError("error parsing user ID") } if !isGlobalAdmin && userDomain != r.Host { - return api.AuthFailed() + return _responses.AuthFailed() } affected, err := maintenance_controller.PurgeUserMedia(userId, beforeTs, rctx) @@ -208,7 +210,7 @@ func PurgeUserMedia(r *http.Request, rctx rcontext.RequestContext, user api.User if err != nil { rctx.Log.Error("Error purging media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error purging media") + return _responses.InternalServerError("error purging media") } mxcs := make([]string, 0) @@ -216,13 +218,13 @@ func PurgeUserMedia(r *http.Request, rctx rcontext.RequestContext, user api.User mxcs = append(mxcs, a.MxcUri()) } - return &api.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} + return &_responses.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} } -func PurgeRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - isGlobalAdmin, isLocalAdmin := api.GetRequestUserAdminStatus(r, rctx, user) +func PurgeRoomMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + isGlobalAdmin, isLocalAdmin := _apimeta.GetRequestUserAdminStatus(r, rctx, user) if !isGlobalAdmin && !isLocalAdmin { - return api.AuthFailed() + return _responses.AuthFailed() } var err error @@ -231,13 +233,11 @@ func PurgeRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api.User if beforeTsStr != "" { beforeTs, err = strconv.ParseInt(beforeTsStr, 10, 64) if err != nil { - return api.BadRequest("Error parsing before_ts: " + err.Error()) + return _responses.BadRequest("Error parsing before_ts: " + err.Error()) } } - params := mux.Vars(r) - - roomId := params["roomId"] + roomId := _routers.GetParam("roomId", r) rctx = rctx.LogWithFields(logrus.Fields{ "roomId": roomId, @@ -248,7 +248,7 @@ func PurgeRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api.User if err != nil { rctx.Log.Error("Error while listing media in the room: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error retrieving media in room") + return _responses.InternalServerError("error retrieving media in room") } mxcs := make([]string, 0) @@ -288,7 +288,7 @@ func PurgeRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api.User if err != nil { rctx.Log.Error("Error purging media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error purging media") + return _responses.InternalServerError("error purging media") } mxcs = make([]string, 0) @@ -296,13 +296,13 @@ func PurgeRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api.User mxcs = append(mxcs, a.MxcUri()) } - return &api.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} + return &_responses.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} } -func PurgeDomainMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - isGlobalAdmin, isLocalAdmin := api.GetRequestUserAdminStatus(r, rctx, user) +func PurgeDomainMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + isGlobalAdmin, isLocalAdmin := _apimeta.GetRequestUserAdminStatus(r, rctx, user) if !isGlobalAdmin && !isLocalAdmin { - return api.AuthFailed() + return _responses.AuthFailed() } var err error @@ -311,13 +311,15 @@ func PurgeDomainMedia(r *http.Request, rctx rcontext.RequestContext, user api.Us if beforeTsStr != "" { beforeTs, err = strconv.ParseInt(beforeTsStr, 10, 64) if err != nil { - return api.BadRequest("Error parsing before_ts: " + err.Error()) + return _responses.BadRequest("Error parsing before_ts: " + err.Error()) } } - params := mux.Vars(r) + serverName := _routers.GetParam("serverName", r) - serverName := params["serverName"] + if !_routers.ServerNameRegex.MatchString(serverName) { + return _responses.BadRequest("invalid server name") + } rctx = rctx.LogWithFields(logrus.Fields{ "serverName": serverName, @@ -325,7 +327,7 @@ func PurgeDomainMedia(r *http.Request, rctx rcontext.RequestContext, user api.Us }) if !isGlobalAdmin && serverName != r.Host { - return api.AuthFailed() + return _responses.AuthFailed() } affected, err := maintenance_controller.PurgeDomainMedia(serverName, beforeTs, rctx) @@ -333,7 +335,7 @@ func PurgeDomainMedia(r *http.Request, rctx rcontext.RequestContext, user api.Us if err != nil { rctx.Log.Error("Error purging media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error purging media") + return _responses.InternalServerError("error purging media") } mxcs := make([]string, 0) @@ -341,5 +343,5 @@ func PurgeDomainMedia(r *http.Request, rctx rcontext.RequestContext, user api.Us mxcs = append(mxcs, a.MxcUri()) } - return &api.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} + return &_responses.DoNotCacheResponse{Payload: map[string]interface{}{"purged": true, "affected": mxcs}} } diff --git a/api/custom/quarantine.go b/api/custom/quarantine.go index 5571ced3e67abddabb4e1420ee78389aa2d7e7fe..4716a1d9b9b39ae076660c835919406653242c00 100644 --- a/api/custom/quarantine.go +++ b/api/custom/quarantine.go @@ -2,12 +2,14 @@ package custom import ( "database/sql" - "github.com/getsentry/sentry-go" "net/http" - "github.com/gorilla/mux" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/internal_cache" "github.com/turt2live/matrix-media-repo/matrix" @@ -23,15 +25,13 @@ type MediaQuarantinedResponse struct { // Developer note: This isn't broken out into a dedicated controller class because the logic is slightly // too complex to do so. If anything, the logic should be improved and moved. -func QuarantineRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func QuarantineRoomMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { canQuarantine, allowOtherHosts, isLocalAdmin := getQuarantineRequestInfo(r, rctx, user) if !canQuarantine { - return api.AuthFailed() + return _responses.AuthFailed() } - params := mux.Vars(r) - - roomId := params["roomId"] + roomId := _routers.GetParam("roomId", r) rctx = rctx.LogWithFields(logrus.Fields{ "roomId": roomId, @@ -42,7 +42,7 @@ func QuarantineRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api if err != nil { rctx.Log.Error("Error while listing media in the room: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error retrieving media in room") + return _responses.InternalServerError("error retrieving media in room") } var mxcs []string @@ -55,7 +55,7 @@ func QuarantineRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api if err != nil { rctx.Log.Error("Error parsing MXC URI (" + mxc + "): " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error parsing mxc uri") + return _responses.InternalServerError("error parsing mxc uri") } if !allowOtherHosts && r.Host != server { @@ -71,18 +71,16 @@ func QuarantineRoomMedia(r *http.Request, rctx rcontext.RequestContext, user api total += resp.(*MediaQuarantinedResponse).NumQuarantined } - return &api.DoNotCacheResponse{Payload: &MediaQuarantinedResponse{NumQuarantined: total}} + return &_responses.DoNotCacheResponse{Payload: &MediaQuarantinedResponse{NumQuarantined: total}} } -func QuarantineUserMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func QuarantineUserMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { canQuarantine, allowOtherHosts, isLocalAdmin := getQuarantineRequestInfo(r, rctx, user) if !canQuarantine { - return api.AuthFailed() + return _responses.AuthFailed() } - params := mux.Vars(r) - - userId := params["userId"] + userId := _routers.GetParam("userId", r) rctx = rctx.LogWithFields(logrus.Fields{ "userId": userId, @@ -93,11 +91,11 @@ func QuarantineUserMedia(r *http.Request, rctx rcontext.RequestContext, user api if err != nil { rctx.Log.Error("Error parsing user ID (" + userId + "): " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error parsing user ID") + return _responses.InternalServerError("error parsing user ID") } if !allowOtherHosts && userDomain != r.Host { - return api.AuthFailed() + return _responses.AuthFailed() } db := storage.GetDatabase().GetMediaStore(rctx) @@ -105,7 +103,7 @@ func QuarantineUserMedia(r *http.Request, rctx rcontext.RequestContext, user api if err != nil { rctx.Log.Error("Error while listing media for the user: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error retrieving media for user") + return _responses.InternalServerError("error retrieving media for user") } total := 0 @@ -118,18 +116,20 @@ func QuarantineUserMedia(r *http.Request, rctx rcontext.RequestContext, user api total += resp.(*MediaQuarantinedResponse).NumQuarantined } - return &api.DoNotCacheResponse{Payload: &MediaQuarantinedResponse{NumQuarantined: total}} + return &_responses.DoNotCacheResponse{Payload: &MediaQuarantinedResponse{NumQuarantined: total}} } -func QuarantineDomainMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func QuarantineDomainMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { canQuarantine, allowOtherHosts, isLocalAdmin := getQuarantineRequestInfo(r, rctx, user) if !canQuarantine { - return api.AuthFailed() + return _responses.AuthFailed() } - params := mux.Vars(r) + serverName := _routers.GetParam("serverName", r) - serverName := params["serverName"] + if !_routers.ServerNameRegex.MatchString(serverName) { + return _responses.BadRequest("invalid server name") + } rctx = rctx.LogWithFields(logrus.Fields{ "serverName": serverName, @@ -137,7 +137,7 @@ func QuarantineDomainMedia(r *http.Request, rctx rcontext.RequestContext, user a }) if !allowOtherHosts && serverName != r.Host { - return api.AuthFailed() + return _responses.AuthFailed() } db := storage.GetDatabase().GetMediaStore(rctx) @@ -145,7 +145,7 @@ func QuarantineDomainMedia(r *http.Request, rctx rcontext.RequestContext, user a if err != nil { rctx.Log.Error("Error while listing media for the server: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error retrieving media for server") + return _responses.InternalServerError("error retrieving media for server") } total := 0 @@ -158,19 +158,21 @@ func QuarantineDomainMedia(r *http.Request, rctx rcontext.RequestContext, user a total += resp.(*MediaQuarantinedResponse).NumQuarantined } - return &api.DoNotCacheResponse{Payload: &MediaQuarantinedResponse{NumQuarantined: total}} + return &_responses.DoNotCacheResponse{Payload: &MediaQuarantinedResponse{NumQuarantined: total}} } -func QuarantineMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func QuarantineMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { canQuarantine, allowOtherHosts, isLocalAdmin := getQuarantineRequestInfo(r, rctx, user) if !canQuarantine { - return api.AuthFailed() + return _responses.AuthFailed() } - params := mux.Vars(r) + server := _routers.GetParam("server", r) + mediaId := _routers.GetParam("mediaId", r) - server := params["server"] - mediaId := params["mediaId"] + if !_routers.ServerNameRegex.MatchString(server) { + return _responses.BadRequest("invalid server ID") + } rctx = rctx.LogWithFields(logrus.Fields{ "server": server, @@ -179,11 +181,11 @@ func QuarantineMedia(r *http.Request, rctx rcontext.RequestContext, user api.Use }) if !allowOtherHosts && r.Host != server { - return api.BadRequest("unable to quarantine media on other homeservers") + return _responses.BadRequest("unable to quarantine media on other homeservers") } resp, _ := doQuarantine(rctx, server, mediaId, allowOtherHosts) - return &api.DoNotCacheResponse{Payload: resp} + return &_responses.DoNotCacheResponse{Payload: resp} } func doQuarantine(ctx rcontext.RequestContext, origin string, mediaId string, allowOtherHosts bool) (interface{}, bool) { @@ -197,7 +199,7 @@ func doQuarantine(ctx rcontext.RequestContext, origin string, mediaId string, al ctx.Log.Error("Error fetching media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error quarantining media"), false + return _responses.InternalServerError("error quarantining media"), false } return doQuarantineOn(media, allowOtherHosts, ctx) @@ -210,7 +212,7 @@ func doQuarantineOn(media *types.Media, allowOtherHosts bool, ctx rcontext.Reque if err != nil { ctx.Log.Error("Error while getting attributes for media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Error quarantining media"), false + return _responses.InternalServerError("Error quarantining media"), false } if attr.Purpose == types.PurposePinned { ctx.Log.Warn("Refusing to quarantine media due to it being pinned") @@ -225,7 +227,7 @@ func doQuarantineOn(media *types.Media, allowOtherHosts bool, ctx rcontext.Reque if err != nil { ctx.Log.Error("Error quarantining media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Error quarantining media"), false + return _responses.InternalServerError("Error quarantining media"), false } return &MediaQuarantinedResponse{NumQuarantined: num}, true @@ -258,7 +260,7 @@ func setMediaQuarantined(media *types.Media, isQuarantined bool, allowOtherHosts return numQuarantined, nil } -func getQuarantineRequestInfo(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) (bool, bool, bool) { +func getQuarantineRequestInfo(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) (bool, bool, bool) { isGlobalAdmin := util.IsGlobalAdmin(user.UserId) || user.IsShared canQuarantine := isGlobalAdmin allowOtherHosts := isGlobalAdmin diff --git a/api/custom/tasks.go b/api/custom/tasks.go index 299330f6361f5a1a9fde53e9e920996706159166..0a390957994e843cd405e3b50e7f7c5d3bbbafd3 100644 --- a/api/custom/tasks.go +++ b/api/custom/tasks.go @@ -2,12 +2,14 @@ package custom import ( "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "net/http" "strconv" - "github.com/gorilla/mux" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/storage" ) @@ -21,14 +23,12 @@ type TaskStatus struct { IsFinished bool `json:"is_finished"` } -func GetTask(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) - - taskIdStr := params["taskId"] +func GetTask(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + taskIdStr := _routers.GetParam("taskId", r) taskId, err := strconv.Atoi(taskIdStr) if err != nil { rctx.Log.Error(err) - return api.BadRequest("invalid task ID") + return _responses.BadRequest("invalid task ID") } rctx = rctx.LogWithFields(logrus.Fields{ @@ -41,10 +41,10 @@ func GetTask(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) i if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("failed to get task information") + return _responses.InternalServerError("failed to get task information") } - return &api.DoNotCacheResponse{Payload: &TaskStatus{ + return &_responses.DoNotCacheResponse{Payload: &TaskStatus{ TaskID: task.ID, Name: task.Name, Params: task.Params, @@ -54,14 +54,14 @@ func GetTask(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) i }} } -func ListAllTasks(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func ListAllTasks(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { db := storage.GetDatabase().GetMetadataStore(rctx) tasks, err := db.GetAllBackgroundTasks() if err != nil { logrus.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Failed to get background tasks") + return _responses.InternalServerError("Failed to get background tasks") } statusObjs := make([]*TaskStatus, 0) @@ -76,17 +76,17 @@ func ListAllTasks(r *http.Request, rctx rcontext.RequestContext, user api.UserIn }) } - return &api.DoNotCacheResponse{Payload: statusObjs} + return &_responses.DoNotCacheResponse{Payload: statusObjs} } -func ListUnfinishedTasks(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func ListUnfinishedTasks(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { db := storage.GetDatabase().GetMetadataStore(rctx) tasks, err := db.GetAllBackgroundTasks() if err != nil { logrus.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Failed to get background tasks") + return _responses.InternalServerError("Failed to get background tasks") } statusObjs := make([]*TaskStatus, 0) @@ -104,5 +104,5 @@ func ListUnfinishedTasks(r *http.Request, rctx rcontext.RequestContext, user api }) } - return &api.DoNotCacheResponse{Payload: statusObjs} + return &_responses.DoNotCacheResponse{Payload: statusObjs} } diff --git a/api/custom/usage.go b/api/custom/usage.go index d954de460743a4886e9a67d1b83a976a31e2b386..98f25ef3cc0c7e0e675dc86800fec05899cee42f 100644 --- a/api/custom/usage.go +++ b/api/custom/usage.go @@ -3,14 +3,16 @@ package custom import ( "encoding/json" "fmt" - "github.com/getsentry/sentry-go" "net/http" "strconv" "strings" - "github.com/gorilla/mux" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/storage/stores" @@ -51,10 +53,12 @@ type MediaUsageEntry struct { CreatedTs int64 `json:"created_ts"` } -func GetDomainUsage(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) +func GetDomainUsage(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + serverName := _routers.GetParam("serverName", r) - serverName := params["serverName"] + if !_routers.ServerNameRegex.MatchString(serverName) { + return _responses.BadRequest("invalid server name") + } rctx = rctx.LogWithFields(logrus.Fields{ "serverName": serverName, @@ -66,17 +70,17 @@ func GetDomainUsage(r *http.Request, rctx rcontext.RequestContext, user api.User if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Failed to get byte usage for server") + return _responses.InternalServerError("Failed to get byte usage for server") } mediaCount, thumbCount, err := db.GetCountUsageForServer(serverName) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Failed to get count usage for server") + return _responses.InternalServerError("Failed to get count usage for server") } - return &api.DoNotCacheResponse{ + return &_responses.DoNotCacheResponse{ Payload: &CountsUsageResponse{ RawBytes: &UsageInfo{ MinimalUsageInfo: &MinimalUsageInfo{ @@ -96,12 +100,14 @@ func GetDomainUsage(r *http.Request, rctx rcontext.RequestContext, user api.User } } -func GetUserUsage(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) - - serverName := params["serverName"] +func GetUserUsage(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + serverName := _routers.GetParam("serverName", r) userIds := r.URL.Query()["user_id"] + if !_routers.ServerNameRegex.MatchString(serverName) { + return _responses.BadRequest("invalid server name") + } + rctx = rctx.LogWithFields(logrus.Fields{ "serverName": serverName, }) @@ -119,7 +125,7 @@ func GetUserUsage(r *http.Request, rctx rcontext.RequestContext, user api.UserIn if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Failed to get media records for users") + return _responses.InternalServerError("Failed to get media records for users") } parsed := make(map[string]*UserUsageEntry) @@ -150,15 +156,17 @@ func GetUserUsage(r *http.Request, rctx rcontext.RequestContext, user api.UserIn entry.UploadedMxcs = append(entry.UploadedMxcs, media.MxcUri()) } - return &api.DoNotCacheResponse{Payload: parsed} + return &_responses.DoNotCacheResponse{Payload: parsed} } -func GetUploadsUsage(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) - - serverName := params["serverName"] +func GetUploadsUsage(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + serverName := _routers.GetParam("serverName", r) mxcs := r.URL.Query()["mxc"] + if !_routers.ServerNameRegex.MatchString(serverName) { + return _responses.BadRequest("invalid server name") + } + rctx = rctx.LogWithFields(logrus.Fields{ "serverName": serverName, }) @@ -176,11 +184,11 @@ func GetUploadsUsage(r *http.Request, rctx rcontext.RequestContext, user api.Use if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Error parsing MXC " + mxc) + return _responses.InternalServerError("Error parsing MXC " + mxc) } if o != serverName { - return api.BadRequest("MXC URIs must match the requested server") + return _responses.BadRequest("MXC URIs must match the requested server") } split = append(split, i) @@ -191,7 +199,7 @@ func GetUploadsUsage(r *http.Request, rctx rcontext.RequestContext, user api.Use if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Failed to get media records for users") + return _responses.InternalServerError("Failed to get media records for users") } parsed := make(map[string]*MediaUsageEntry) @@ -210,21 +218,24 @@ func GetUploadsUsage(r *http.Request, rctx rcontext.RequestContext, user api.Use } } - return &api.DoNotCacheResponse{Payload: parsed} + return &_responses.DoNotCacheResponse{Payload: parsed} } // GetUsersUsageStats attempts to provide a loose equivalent to this Synapse admin end-point: // https://matrix-org.github.io/synapse/develop/admin_api/statistics.html#users-media-usage-statistics -func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) +func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { qs := r.URL.Query() var err error - serverName := params["serverName"] + serverName := _routers.GetParam("serverName", r) + + if !_routers.ServerNameRegex.MatchString(serverName) { + return _responses.BadRequest("invalid server name") + } - isGlobalAdmin, isLocalAdmin := api.GetRequestUserAdminStatus(r, rctx, user) + isGlobalAdmin, isLocalAdmin := _apimeta.GetRequestUserAdminStatus(r, rctx, user) if !isGlobalAdmin && (serverName != r.Host || !isLocalAdmin) { - return api.AuthFailed() + return _responses.AuthFailed() } orderBy := qs.Get("order_by") @@ -234,7 +245,7 @@ func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api. if !util.ArrayContains(stores.UsersUsageStatsSorts, orderBy) { acceptedValsStr, _ := json.Marshal(stores.UsersUsageStatsSorts) acceptedValsStr = []byte(strings.ReplaceAll(string(acceptedValsStr), "\"", "'")) - return api.BadRequest( + return _responses.BadRequest( fmt.Sprintf("Query parameter 'order_by' must be one of %s", acceptedValsStr)) } @@ -242,7 +253,7 @@ func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api. if len(qs["from"]) > 0 { start, err = strconv.ParseInt(qs.Get("from"), 10, 64) if err != nil || start < 0 { - return api.BadRequest("Query parameter 'from' must be a non-negative integer") + return _responses.BadRequest("Query parameter 'from' must be a non-negative integer") } } @@ -250,7 +261,7 @@ func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api. if len(qs["limit"]) > 0 { limit, err = strconv.ParseInt(qs.Get("limit"), 10, 64) if err != nil || limit < 0 { - return api.BadRequest("Query parameter 'limit' must be a non-negative integer") + return _responses.BadRequest("Query parameter 'limit' must be a non-negative integer") } } @@ -259,7 +270,7 @@ func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api. if len(qs["from_ts"]) > 0 { fromTS, err = strconv.ParseInt(qs.Get("from_ts"), 10, 64) if err != nil || fromTS < 0 { - return api.BadRequest("Query parameter 'from_ts' must be a non-negative integer") + return _responses.BadRequest("Query parameter 'from_ts' must be a non-negative integer") } } @@ -267,15 +278,15 @@ func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api. if len(qs["until_ts"]) > 0 { untilTS, err = strconv.ParseInt(qs.Get("until_ts"), 10, 64) if err != nil || untilTS < 0 { - return api.BadRequest("Query parameter 'until_ts' must be a non-negative integer") + return _responses.BadRequest("Query parameter 'until_ts' must be a non-negative integer") } else if untilTS <= fromTS { - return api.BadRequest("Query parameter 'until_ts' must be greater than 'from_ts'") + return _responses.BadRequest("Query parameter 'until_ts' must be greater than 'from_ts'") } } searchTerm := qs.Get("search_term") if searchTerm == "" && len(qs["search_term"]) > 0 { - return api.BadRequest("Query parameter 'search_term' cannot be an empty string") + return _responses.BadRequest("Query parameter 'search_term' cannot be an empty string") } isAscendingOrder := true @@ -285,7 +296,7 @@ func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api. } else if direction == "b" { isAscendingOrder = false } else { - return api.BadRequest("Query parameter 'dir' must be one of ['f', 'b']") + return _responses.BadRequest("Query parameter 'dir' must be one of ['f', 'b']") } rctx = rctx.LogWithFields(logrus.Fields{ @@ -314,7 +325,7 @@ func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api. if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("Failed to get users' usage stats on specified server") + return _responses.InternalServerError("Failed to get users' usage stats on specified server") } var users []map[string]interface{} @@ -338,5 +349,5 @@ func GetUsersUsageStats(r *http.Request, rctx rcontext.RequestContext, user api. result["next_token"] = start + int64(len(stats)) } - return &api.DoNotCacheResponse{Payload: result} + return &_responses.DoNotCacheResponse{Payload: result} } diff --git a/api/custom/version.go b/api/custom/version.go index f9bd53b93a3e43bcf9ef004e8ce4fa1f8e951368..dbcff87cb61150beb0cd15a1916de53ccb421775 100644 --- a/api/custom/version.go +++ b/api/custom/version.go @@ -3,15 +3,16 @@ package custom import ( "net/http" - "github.com/turt2live/matrix-media-repo/api" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/common/version" ) -func GetVersion(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func GetVersion(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { unstableFeatures := make(map[string]bool) - return &api.DoNotCacheResponse{ + return &_responses.DoNotCacheResponse{ Payload: map[string]interface{}{ "Version": version.Version, "GitCommit": version.GitCommit, diff --git a/api/features/feature_routes.go b/api/features/feature_routes.go deleted file mode 100644 index 442d251b45efc834ef6a3ecc975fe1d275a82033..0000000000000000000000000000000000000000 --- a/api/features/feature_routes.go +++ /dev/null @@ -1,15 +0,0 @@ -package features - -import ( - "net/http" -) - -const IPFSDownloadRoute = "/_matrix/media/unstable/io.t2bot.ipfs/download/{server:[a-zA-Z0-9.:\\-_]+}/{ipfsContentId:[^/]+}" -const IPFSLiveDownloadRouteR0 = "/_matrix/media/r0/download/{server:[a-zA-Z0-9.:\\-_]+}/ipfs:{ipfsContentId:[^/]+}" -const IPFSLiveDownloadRouteV1 = "/_matrix/media/v1/download/{server:[a-zA-Z0-9.:\\-_]+}/ipfs:{ipfsContentId:[^/]+}" -const IPFSLiveDownloadRouteUnstable = "/_matrix/media/v1/download/{server:[a-zA-Z0-9.:\\-_]+}/ipfs:{ipfsContentId:[^/]+}" - -func IsRoute(r *http.Request, route string) bool { - uri := r.URL.Path - return uri == route -} diff --git a/api/general_handlers.go b/api/general_handlers.go deleted file mode 100644 index 1c20046008ff2b91b0d3b44c37fd8d5c6b2d5da4..0000000000000000000000000000000000000000 --- a/api/general_handlers.go +++ /dev/null @@ -1,19 +0,0 @@ -package api - -import ( - "net/http" - - "github.com/turt2live/matrix-media-repo/common/rcontext" -) - -func NotFoundHandler(r *http.Request, rctx rcontext.RequestContext) interface{} { - return NotFoundError() -} - -func MethodNotAllowedHandler(r *http.Request, rctx rcontext.RequestContext) interface{} { - return MethodNotAllowed() -} - -func EmptyResponseHandler(r *http.Request, rctx rcontext.RequestContext) interface{} { - return &EmptyResponse{} -} diff --git a/api/r0/download.go b/api/r0/download.go index d84c74ec5b5f6a2d99f22a3ef27caf6132ca5d18..5b988220de6df5399e445e0ebd471356bd9af2a1 100644 --- a/api/r0/download.go +++ b/api/r0/download.go @@ -1,35 +1,32 @@ package r0 import ( - "github.com/getsentry/sentry-go" - "io" "net/http" "strconv" - "github.com/gorilla/mux" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/download_controller" ) -type DownloadMediaResponse struct { - ContentType string - Filename string - SizeBytes int64 - Data io.ReadCloser - TargetDisposition string -} +type DownloadMediaResponse = _responses.DownloadResponse -func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) - - server := params["server"] - mediaId := params["mediaId"] - filename := params["filename"] +func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + server := _routers.GetParam("server", r) + mediaId := _routers.GetParam("mediaId", r) + filename := _routers.GetParam("filename", r) allowRemote := r.URL.Query().Get("allow_remote") + if !_routers.ServerNameRegex.MatchString(server) { + return _responses.BadRequest("invalid server ID") + } + targetDisposition := r.URL.Query().Get("org.matrix.msc2702.asAttachment") if targetDisposition == "true" { targetDisposition = "attachment" @@ -43,7 +40,7 @@ func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI if allowRemote != "" { parsedFlag, err := strconv.ParseBool(allowRemote) if err != nil { - return api.InternalServerError("allow_remote flag does not appear to be a boolean") + return _responses.InternalServerError("allow_remote flag does not appear to be a boolean") } downloadRemote = parsedFlag } @@ -58,15 +55,15 @@ func DownloadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserI streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, false, rctx) if err != nil { if err == common.ErrMediaNotFound { - return api.NotFoundError() + return _responses.NotFoundError() } else if err == common.ErrMediaTooLarge { - return api.RequestTooLarge() + return _responses.RequestTooLarge() } else if err == common.ErrMediaQuarantined { - return api.NotFoundError() // We lie for security + return _responses.NotFoundError() // We lie for security } rctx.Log.Error("Unexpected error locating media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } if filename == "" { diff --git a/api/r0/identicon.go b/api/r0/identicon.go index 9fa756e3bcadfd817695de58826ef1f3d027cdc3..18387ccd34f139342d7375a7d223511c80ab2042 100644 --- a/api/r0/identicon.go +++ b/api/r0/identicon.go @@ -3,31 +3,28 @@ package r0 import ( "bytes" "crypto/md5" - "github.com/getsentry/sentry-go" "image/color" "io" "net/http" "strconv" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/cupcake/sigil/gen" "github.com/disintegration/imaging" - "github.com/gorilla/mux" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/rcontext" ) -type IdenticonResponse struct { - Avatar io.Reader -} - -func Identicon(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func Identicon(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.Identicons.Enabled { - return api.NotFoundError() + return _responses.NotFoundError() } - params := mux.Vars(r) - seed := params["seed"] + seed := _routers.GetParam("seed", r) var err error width := 96 @@ -38,14 +35,14 @@ func Identicon(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) if widthStr != "" { width, err = strconv.Atoi(widthStr) if err != nil { - return api.InternalServerError("Error parsing width: " + err.Error()) + return _responses.InternalServerError("Error parsing width: " + err.Error()) } height = width } if heightStr != "" { height, err = strconv.Atoi(heightStr) if err != nil { - return api.InternalServerError("Error parsing height: " + err.Error()) + return _responses.InternalServerError("Error parsing height: " + err.Error()) } } @@ -86,10 +83,16 @@ func Identicon(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) if err != nil { rctx.Log.Error("Error generating image:" + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("error generating identicon") + return _responses.InternalServerError("error generating identicon") } - return &IdenticonResponse{Avatar: imgData} + return &_responses.DownloadResponse{ + ContentType: "image/png", + Filename: string(hashed) + ".png", + SizeBytes: 0, + Data: io.NopCloser(imgData), + TargetDisposition: "inline", + } } func rgb(r, g, b uint8) color.NRGBA { diff --git a/api/r0/logout.go b/api/r0/logout.go index fc92f986844754ad014974dc347a458cfe3defae..3a81eefe4ab5e9428ead7aac7e907b887d91296f 100644 --- a/api/r0/logout.go +++ b/api/r0/logout.go @@ -2,29 +2,31 @@ package r0 import ( "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "net/http" - "github.com/turt2live/matrix-media-repo/api" - "github.com/turt2live/matrix-media-repo/api/auth_cache" + "github.com/turt2live/matrix-media-repo/api/_auth_cache" "github.com/turt2live/matrix-media-repo/common/rcontext" ) -func Logout(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - err := auth_cache.InvalidateToken(rctx, user.AccessToken, user.UserId) +func Logout(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + err := _auth_cache.InvalidateToken(rctx, user.AccessToken, user.UserId) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("unable to logout") + return _responses.InternalServerError("unable to logout") } - return api.EmptyResponse{} + return _responses.EmptyResponse{} } -func LogoutAll(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - err := auth_cache.InvalidateAllTokens(rctx, user.AccessToken, user.UserId) +func LogoutAll(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + err := _auth_cache.InvalidateAllTokens(rctx, user.AccessToken, user.UserId) if err != nil { rctx.Log.Error(err) sentry.CaptureException(err) - return api.InternalServerError("unable to logout") + return _responses.InternalServerError("unable to logout") } - return api.EmptyResponse{} + return _responses.EmptyResponse{} } diff --git a/api/r0/preview_url.go b/api/r0/preview_url.go index 98eac2d42150cfad77864e88c768721105fd65ee..c761a4f0908cb97083e537696b04660fabfe77ba 100644 --- a/api/r0/preview_url.go +++ b/api/r0/preview_url.go @@ -2,11 +2,13 @@ package r0 import ( "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "net/http" "strconv" "strings" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/preview_controller" @@ -26,9 +28,9 @@ type MatrixOpenGraph struct { ImageHeight int `json:"og:image:height,omitempty"` } -func PreviewUrl(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func PreviewUrl(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { if !rctx.Config.UrlPreviews.Enabled { - return api.NotFoundError() + return _responses.NotFoundError() } params := r.URL.Query() @@ -42,16 +44,16 @@ func PreviewUrl(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo ts, err = strconv.ParseInt(tsStr, 10, 64) if err != nil { rctx.Log.Error("Error parsing ts: " + err.Error()) - return api.BadRequest(err.Error()) + return _responses.BadRequest(err.Error()) } } // Validate the URL if urlStr == "" { - return api.BadRequest("No url provided") + return _responses.BadRequest("No url provided") } if strings.Index(urlStr, "http://") != 0 && strings.Index(urlStr, "https://") != 0 { - return api.BadRequest("Scheme not accepted") + return _responses.BadRequest("Scheme not accepted") } languageHeader := rctx.Config.UrlPreviews.DefaultLanguage @@ -62,12 +64,12 @@ func PreviewUrl(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo preview, err := preview_controller.GetPreview(urlStr, r.Host, user.UserId, ts, languageHeader, rctx) if err != nil { if err == common.ErrMediaNotFound || err == common.ErrHostNotFound { - return api.NotFoundError() + return _responses.NotFoundError() } else if err == common.ErrInvalidHost || err == common.ErrHostBlacklisted { - return api.BadRequest(err.Error()) + return _responses.BadRequest(err.Error()) } else { sentry.CaptureException(err) - return api.InternalServerError("unexpected error during request") + return _responses.InternalServerError("unexpected error during request") } } diff --git a/api/r0/public_config.go b/api/r0/public_config.go index 66d313f2e386fd02c96f43aa16d0aa87666701e6..fc9bf3d6830c9795039411814740556120818726 100644 --- a/api/r0/public_config.go +++ b/api/r0/public_config.go @@ -3,7 +3,7 @@ package r0 import ( "net/http" - "github.com/turt2live/matrix-media-repo/api" + "github.com/turt2live/matrix-media-repo/api/_apimeta" "github.com/turt2live/matrix-media-repo/common/rcontext" ) @@ -11,7 +11,7 @@ type PublicConfigResponse struct { UploadMaxSize int64 `json:"m.upload.size,omitempty"` } -func PublicConfig(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func PublicConfig(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { uploadSize := rctx.Config.Uploads.ReportedMaxSizeBytes if uploadSize == 0 { uploadSize = rctx.Config.Uploads.MaxSizeBytes diff --git a/api/r0/thumbnail.go b/api/r0/thumbnail.go index b1b73f01a6a8b072c53eed0961a157b363c6e691..7e56131e9fccb8de2c4143c7bc2fb2db6fc04426 100644 --- a/api/r0/thumbnail.go +++ b/api/r0/thumbnail.go @@ -2,29 +2,33 @@ package r0 import ( "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "net/http" "strconv" - "github.com/gorilla/mux" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/thumbnail_controller" ) -func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) - - server := params["server"] - mediaId := params["mediaId"] +func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + server := _routers.GetParam("server", r) + mediaId := _routers.GetParam("mediaId", r) allowRemote := r.URL.Query().Get("allow_remote") + if !_routers.ServerNameRegex.MatchString(server) { + return _responses.BadRequest("invalid server ID") + } + downloadRemote := true if allowRemote != "" { parsedFlag, err := strconv.ParseBool(allowRemote) if err != nil { - return api.BadRequest("allow_remote flag does not appear to be a boolean") + return _responses.BadRequest("allow_remote flag does not appear to be a boolean") } downloadRemote = parsedFlag } @@ -44,7 +48,7 @@ func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user api.User } if widthStr == "" || heightStr == "" { - return api.BadRequest("Width and height are required") + return _responses.BadRequest("Width and height are required") } width := 0 @@ -54,21 +58,21 @@ func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user api.User if widthStr != "" { parsedWidth, err := strconv.Atoi(widthStr) if err != nil { - return api.BadRequest("Width does not appear to be an integer") + return _responses.BadRequest("Width does not appear to be an integer") } width = parsedWidth } if heightStr != "" { parsedHeight, err := strconv.Atoi(heightStr) if err != nil { - return api.BadRequest("Height does not appear to be an integer") + return _responses.BadRequest("Height does not appear to be an integer") } height = parsedHeight } if animatedStr != "" { parsedFlag, err := strconv.ParseBool(animatedStr) if err != nil { - return api.BadRequest("Animated flag does not appear to be a boolean") + return _responses.BadRequest("Animated flag does not appear to be a boolean") } animated = parsedFlag } @@ -84,19 +88,19 @@ func ThumbnailMedia(r *http.Request, rctx rcontext.RequestContext, user api.User }) if width <= 0 || height <= 0 { - return api.BadRequest("Width and height must be greater than zero") + return _responses.BadRequest("Width and height must be greater than zero") } streamedThumbnail, err := thumbnail_controller.GetThumbnail(server, mediaId, width, height, animated, method, downloadRemote, rctx) if err != nil { if err == common.ErrMediaNotFound { - return api.NotFoundError() + return _responses.NotFoundError() } else if err == common.ErrMediaTooLarge { - return api.RequestTooLarge() + return _responses.RequestTooLarge() } rctx.Log.Error("Unexpected error locating media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } return &DownloadMediaResponse{ diff --git a/api/r0/upload.go b/api/r0/upload.go index 63b0170beb0578b4cdfea0fa07a5add47b8b7dd2..1db122493f1b80e7d4c9fa146fe63997fd1b7317 100644 --- a/api/r0/upload.go +++ b/api/r0/upload.go @@ -2,19 +2,21 @@ package r0 import ( "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "io" "io/ioutil" "net/http" "path/filepath" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/info_controller" "github.com/turt2live/matrix-media-repo/controllers/upload_controller" "github.com/turt2live/matrix-media-repo/quota" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) type MediaUploadedResponse struct { @@ -22,9 +24,9 @@ type MediaUploadedResponse struct { Blurhash string `json:"xyz.amorgan.blurhash,omitempty"` } -func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { +func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { filename := filepath.Base(r.URL.Query().Get("filename")) - defer cleanup.DumpAndCloseStream(r.Body) + defer stream_util.DumpAndCloseStream(r.Body) rctx = rctx.LogWithFields(logrus.Fields{ "filename": filename, @@ -37,12 +39,12 @@ func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInf if upload_controller.IsRequestTooLarge(r.ContentLength, r.Header.Get("Content-Length"), rctx) { io.Copy(ioutil.Discard, r.Body) // Ditch the entire request - return api.RequestTooLarge() + return _responses.RequestTooLarge() } if upload_controller.IsRequestTooSmall(r.ContentLength, r.Header.Get("Content-Length"), rctx) { io.Copy(ioutil.Discard, r.Body) // Ditch the entire request - return api.RequestTooSmall() + return _responses.RequestTooSmall() } inQuota, err := quota.IsUserWithinQuota(rctx, user.UserId) @@ -50,11 +52,11 @@ func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInf io.Copy(ioutil.Discard, r.Body) // Ditch the entire request rctx.Log.Error("Unexpected error checking quota: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } if !inQuota { io.Copy(ioutil.Discard, r.Body) // Ditch the entire request - return api.QuotaExceeded() + return _responses.QuotaExceeded() } contentLength := upload_controller.EstimateContentLength(r.ContentLength, r.Header.Get("Content-Length")) @@ -64,12 +66,12 @@ func UploadMedia(r *http.Request, rctx rcontext.RequestContext, user api.UserInf io.Copy(ioutil.Discard, r.Body) // Ditch the entire request if err == common.ErrMediaQuarantined { - return api.BadRequest("This file is not permitted on this server") + return _responses.BadRequest("This file is not permitted on this server") } rctx.Log.Error("Unexpected error storing media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } if rctx.Config.Features.MSC2448Blurhash.Enabled && r.URL.Query().Get("xyz.amorgan.generate_blurhash") == "true" { diff --git a/api/router.go b/api/router.go new file mode 100644 index 0000000000000000000000000000000000000000..8e49a33b59270434473832e0a26724193994c971 --- /dev/null +++ b/api/router.go @@ -0,0 +1,78 @@ +package api + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + + "github.com/getsentry/sentry-go" + "github.com/julienschmidt/httprouter" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/api/_responses" +) + +func buildPrimaryRouter() *httprouter.Router { + router := httprouter.New() + router.RedirectTrailingSlash = false // spec compliance + router.RedirectFixedPath = false // don't fix case + router.MethodNotAllowed = http.HandlerFunc(methodNotAllowedFn) + router.NotFound = http.HandlerFunc(notFoundFn) + //router.GlobalOPTIONS = http.HandlerFunc(corsFn) + router.PanicHandler = panicFn + return router +} + +func methodNotAllowedFn(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusMethodNotAllowed) + if b, err := json.Marshal(_responses.MethodNotAllowed()); err != nil { + panic(errors.New("error preparing MethodNotAllowed: " + err.Error())) + } else { + if _, err = w.Write(b); err != nil { + panic(errors.New("error sending MethodNotAllowed: " + err.Error())) + } + } +} + +func notFoundFn(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusNotFound) + if b, err := json.Marshal(_responses.NotFoundError()); err != nil { + panic(errors.New("error preparing NotFound: " + err.Error())) + } else { + if _, err = w.Write(b); err != nil { + panic(errors.New("error sending NotFound: " + err.Error())) + } + } +} + +//func corsFn(w http.ResponseWriter, r *http.Request) { +// header := w.Header() +// if header.Get("Access-Control-Request-Method") != "" { +// header.Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization") +// header.Set("Access-Control-Allow-Origin", "Access-Control-Allow-Origin") +// } +// +// w.WriteHeader(http.StatusNoContent) +//} + +func panicFn(w http.ResponseWriter, r *http.Request, i interface{}) { + logrus.Errorf("Panic received on %s %s: %s", r.Method, r.URL.String(), i) + + if e, ok := i.(error); ok { + sentry.CaptureException(e) + } else { + sentry.CaptureMessage(fmt.Sprintf("Unknown panic received: %T %s %+v", i, i, i)) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusInternalServerError) + if b, err := json.Marshal(_responses.InternalServerError("unexpected error")); err != nil { + panic(errors.New("error preparing InternalServerError: " + err.Error())) + } else { + if _, err = w.Write(b); err != nil { + panic(errors.New("error sending InternalServerError: " + err.Error())) + } + } +} diff --git a/api/routes.go b/api/routes.go new file mode 100644 index 0000000000000000000000000000000000000000..7b81d67afad8ee105a448594a525736a61bad7cd --- /dev/null +++ b/api/routes.go @@ -0,0 +1,124 @@ +package api + +import ( + "fmt" + "net/http" + "os" + "strings" + + "github.com/julienschmidt/httprouter" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/turt2live/matrix-media-repo/api/custom" + "github.com/turt2live/matrix-media-repo/api/r0" + "github.com/turt2live/matrix-media-repo/api/unstable" + "github.com/turt2live/matrix-media-repo/api/webserver/debug" +) + +const PrefixMedia = "/_matrix/media" +const PrefixClient = "/_matrix/client" + +func buildRoutes() http.Handler { + counter := &_routers.RequestCounter{} + router := buildPrimaryRouter() + + pprofSecret := os.Getenv("MEDIA_PPROF_SECRET_KEY") + if pprofSecret != "" { + logrus.Warn("Enabling pprof/debug http endpoints") + debug.BindPprofEndpoints(router, pprofSecret) + } + + // Standard (spec) features + register([]string{"POST"}, PrefixMedia, "upload", false, router, makeRoute(_routers.RequireAccessToken(r0.UploadMedia), "upload", false, counter)) + downloadRoute := makeRoute(_routers.OptionalAccessToken(r0.DownloadMedia), "download", false, counter) + register([]string{"GET"}, PrefixMedia, "download/:server/:mediaId/:filename", false, router, downloadRoute) + register([]string{"GET"}, PrefixMedia, "download/:server/:mediaId", false, router, downloadRoute) + register([]string{"GET"}, PrefixMedia, "thumbnail/:server/:mediaId", false, router, makeRoute(_routers.OptionalAccessToken(r0.ThumbnailMedia), "thumbnail", false, counter)) + register([]string{"GET"}, PrefixMedia, "preview_url", false, router, makeRoute(_routers.RequireAccessToken(r0.PreviewUrl), "url_preview", false, counter)) + register([]string{"GET"}, PrefixMedia, "identicon/*seed", false, router, makeRoute(_routers.OptionalAccessToken(r0.Identicon), "identicon", false, counter)) + register([]string{"GET"}, PrefixMedia, "config", false, router, makeRoute(_routers.RequireAccessToken(r0.PublicConfig), "config", false, counter)) + register([]string{"POST"}, PrefixClient, "logout", false, router, makeRoute(_routers.RequireAccessToken(r0.Logout), "logout", false, counter)) + register([]string{"POST"}, PrefixClient, "logout/all", false, router, makeRoute(_routers.RequireAccessToken(r0.LogoutAll), "logout_all", false, counter)) + + // Custom features + register([]string{"GET"}, PrefixMedia, "local_copy/:server/:mediaId", true, router, makeRoute(_routers.RequireAccessToken(unstable.LocalCopy), "local_copy", false, counter)) + register([]string{"GET"}, PrefixMedia, "info/:server/:mediaId", true, router, makeRoute(_routers.RequireAccessToken(unstable.MediaInfo), "info", false, counter)) + purgeOneRoute := makeRoute(_routers.RequireAccessToken(custom.PurgeIndividualRecord), "purge_individual_media", false, counter) + register([]string{"DELETE"}, PrefixMedia, "download/:server/:mediaId", true, router, purgeOneRoute) + + // Custom and top-level features + router.Handler("GET", fmt.Sprintf("%s/version", PrefixMedia), makeRoute(_routers.OptionalAccessToken(custom.GetVersion), "get_version", false, counter)) + healthzRoute := makeRoute(_routers.OptionalAccessToken(custom.GetHealthz), "healthz", true, counter) + router.Handler("GET", "/healthz", healthzRoute) + router.Handler("HEAD", "/healthz", healthzRoute) + + // All admin routes are unstable only + purgeRemoteRoute := makeRoute(_routers.RequireRepoAdmin(custom.PurgeRemoteMedia), "purge_remote_media", false, counter) + register([]string{"POST"}, PrefixMedia, "admin/purge_remote", true, router, purgeRemoteRoute) + register([]string{"POST"}, PrefixMedia, "admin/purge/remote", true, router, purgeRemoteRoute) + register([]string{"POST"}, PrefixClient, "admin/purge_media_cache", true, router, purgeRemoteRoute) // synapse compat + register([]string{"POST"}, PrefixMedia, "admin/purge/media/:server/:mediaId", true, router, purgeOneRoute) + register([]string{"POST"}, PrefixMedia, "admin/purge/old", true, router, makeRoute(_routers.RequireRepoAdmin(custom.PurgeOldMedia), "purge_old_media", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/purge/quarantined", true, router, makeRoute(_routers.RequireAccessToken(custom.PurgeQuarantined), "purge_quarantined", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/purge/user/:userId", true, router, makeRoute(_routers.RequireAccessToken(custom.PurgeUserMedia), "purge_user_media", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/purge/room/:roomId", true, router, makeRoute(_routers.RequireAccessToken(custom.PurgeRoomMedia), "purge_room_media", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/purge/server/:serverName", true, router, makeRoute(_routers.RequireAccessToken(custom.PurgeDomainMedia), "purge_domain_media", false, counter)) + quarantineRoomRoute := makeRoute(_routers.RequireAccessToken(custom.QuarantineRoomMedia), "quarantine_room", false, counter) + register([]string{"POST"}, PrefixMedia, "admin/quarantine/room/:roomId", true, router, quarantineRoomRoute) + register([]string{"POST"}, PrefixClient, "admin/quarantine_media/:roomId", true, router, quarantineRoomRoute) // synapse compat + register([]string{"POST"}, PrefixMedia, "admin/quarantine/user/:userId", true, router, makeRoute(_routers.RequireAccessToken(custom.QuarantineUserMedia), "quarantine_user", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/quarantine/server/:serverName", true, router, makeRoute(_routers.RequireAccessToken(custom.QuarantineDomainMedia), "quarantine_domain", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/quarantine/media/:server/:mediaId", true, router, makeRoute(_routers.RequireAccessToken(custom.QuarantineMedia), "quarantine_media", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/datastores/:datastoreId/size_estimate", true, router, makeRoute(_routers.RequireRepoAdmin(custom.GetDatastoreStorageEstimate), "get_storage_estimate", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/datastores/:sourceDsId/transfer_to/:targetDsId", true, router, makeRoute(_routers.RequireRepoAdmin(custom.MigrateBetweenDatastores), "datastore_transfer", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/datastores", true, router, makeRoute(_routers.RequireRepoAdmin(custom.GetDatastores), "list_datastores", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/federation/test/:serverName", true, router, makeRoute(_routers.RequireRepoAdmin(custom.GetFederationInfo), "federation_test", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/usage/:serverName", true, router, makeRoute(_routers.RequireRepoAdmin(custom.GetDomainUsage), "domain_usage", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/usage/:serverName/users", true, router, makeRoute(_routers.RequireRepoAdmin(custom.GetUserUsage), "user_usage", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/usage/:serverName/users-stats", true, router, makeRoute(_routers.RequireAccessToken(custom.GetUsersUsageStats), "users_usage_stats", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/usage/:serverName/uploads", true, router, makeRoute(_routers.RequireRepoAdmin(custom.GetUploadsUsage), "uploads_usage", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/task/:taskId", true, router, makeRoute(_routers.RequireRepoAdmin(custom.GetTask), "get_background_task", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/tasks/all", true, router, makeRoute(_routers.RequireRepoAdmin(custom.ListAllTasks), "list_all_background_tasks", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/tasks/unfinished", true, router, makeRoute(_routers.RequireRepoAdmin(custom.ListUnfinishedTasks), "list_unfinished_background_tasks", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/user/:userId/export", true, router, makeRoute(_routers.RequireAccessToken(custom.ExportUserData), "export_user_data", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/server/:serverName/export", true, router, makeRoute(_routers.RequireAccessToken(custom.ExportServerData), "export_server_data", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/export/:exportId/view", true, router, makeRoute(_routers.OptionalAccessToken(custom.ViewExport), "view_export", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/export/:exportId/metadata", true, router, makeRoute(_routers.OptionalAccessToken(custom.GetExportMetadata), "get_export_metadata", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/export/:exportId/part/:partId", true, router, makeRoute(_routers.OptionalAccessToken(custom.DownloadExportPart), "download_export_part", false, counter)) + register([]string{"DELETE"}, PrefixMedia, "admin/export/:exportId/delete", true, router, makeRoute(_routers.OptionalAccessToken(custom.DeleteExport), "delete_export", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/import", true, router, makeRoute(_routers.RequireRepoAdmin(custom.StartImport), "start_import", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/import/:importId/part", true, router, makeRoute(_routers.RequireRepoAdmin(custom.AppendToImport), "append_to_import", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/import/:importId/close", true, router, makeRoute(_routers.RequireRepoAdmin(custom.StopImport), "stop_import", false, counter)) + register([]string{"GET"}, PrefixMedia, "admin/media/:server/:mediaId/attributes", true, router, makeRoute(_routers.RequireAccessToken(custom.GetAttributes), "get_media_attributes", false, counter)) + register([]string{"POST"}, PrefixMedia, "admin/media/:server/:mediaId/attributes", true, router, makeRoute(_routers.RequireAccessToken(custom.SetAttributes), "set_media_attributes", false, counter)) + + // TODO: Register pprof + + return router +} + +func makeRoute(generator _routers.GeneratorFn, name string, ignoreHost bool, counter *_routers.RequestCounter) http.Handler { + return _routers.NewInstallMetadataRouter(ignoreHost, name, counter, + _routers.NewInstallHeadersRouter( + _routers.NewHostRouter( + _routers.NewMetricsRequestRouter( + _routers.NewRContextRouter(generator, _routers.NewMetricsResponseRouter(nil)), + ), + ), + )) +} + +var versions = []string{"r0", "v1", "v3", "unstable", "unstable/io.t2bot.media"} + +func register(methods []string, prefix string, postfix string, unstableOnly bool, router *httprouter.Router, handler http.Handler) { + for _, method := range methods { + for _, version := range versions { + if unstableOnly && !strings.HasPrefix(version, "unstable") { + continue + } + path := fmt.Sprintf("%s/%s/%s", prefix, version, postfix) + router.Handler(method, path, handler) + logrus.Debug("Registering route: ", method, path) + } + } +} diff --git a/api/unstable/info.go b/api/unstable/info.go index 448e0183f6e044a8db513fdd5072babf9fb7fe72..e47542e32b159b5f7074f01329e15fc9afdb4cba 100644 --- a/api/unstable/info.go +++ b/api/unstable/info.go @@ -3,23 +3,25 @@ package unstable import ( "bytes" "database/sql" - "github.com/getsentry/sentry-go" "io/ioutil" "net/http" "strconv" "strings" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/disintegration/imaging" - "github.com/gorilla/mux" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/download_controller" "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/thumbnailing" "github.com/turt2live/matrix-media-repo/thumbnailing/i" - "github.com/turt2live/matrix-media-repo/util/cleanup" "github.com/turt2live/matrix-media-repo/util/util_byte_seeker" ) @@ -47,18 +49,20 @@ type MediaInfoResponse struct { NumChannels int `json:"num_channels,omitempty"` } -func MediaInfo(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) - - server := params["server"] - mediaId := params["mediaId"] +func MediaInfo(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + server := _routers.GetParam("server", r) + mediaId := _routers.GetParam("mediaId", r) allowRemote := r.URL.Query().Get("allow_remote") + if !_routers.ServerNameRegex.MatchString(server) { + return _responses.BadRequest("invalid server ID") + } + downloadRemote := true if allowRemote != "" { parsedFlag, err := strconv.ParseBool(allowRemote) if err != nil { - return api.InternalServerError("allow_remote flag does not appear to be a boolean") + return _responses.InternalServerError("allow_remote flag does not appear to be a boolean") } downloadRemote = parsedFlag } @@ -72,23 +76,23 @@ func MediaInfo(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, rctx) if err != nil { if err == common.ErrMediaNotFound { - return api.NotFoundError() + return _responses.NotFoundError() } else if err == common.ErrMediaTooLarge { - return api.RequestTooLarge() + return _responses.RequestTooLarge() } else if err == common.ErrMediaQuarantined { - return api.NotFoundError() // We lie for security + return _responses.NotFoundError() // We lie for security } rctx.Log.Error("Unexpected error locating media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } - defer cleanup.DumpAndCloseStream(streamedMedia.Stream) + defer stream_util.DumpAndCloseStream(streamedMedia.Stream) b, err := ioutil.ReadAll(streamedMedia.Stream) if err != nil { rctx.Log.Error("Unexpected error processing media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } response := &MediaInfoResponse{ @@ -111,7 +115,7 @@ func MediaInfo(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) if err != nil && err != sql.ErrNoRows { rctx.Log.Error("Unexpected error locating media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } if thumbs != nil && len(thumbs) > 0 { diff --git a/api/unstable/ipfs_download.go b/api/unstable/ipfs_download.go deleted file mode 100644 index 5b20d1d8f41442dc93e3da4581fed187033fd9e9..0000000000000000000000000000000000000000 --- a/api/unstable/ipfs_download.go +++ /dev/null @@ -1,49 +0,0 @@ -package unstable - -import ( - "github.com/getsentry/sentry-go" - "net/http" - - "github.com/gorilla/mux" - "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" - "github.com/turt2live/matrix-media-repo/api/r0" - "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/ipfs_proxy" -) - -func IPFSDownload(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) - - server := params["server"] - ipfsContentId := params["ipfsContentId"] - - targetDisposition := r.URL.Query().Get("org.matrix.msc2702.asAttachment") - if targetDisposition == "true" { - targetDisposition = "attachment" - } else if targetDisposition == "false" { - targetDisposition = "inline" - } else { - targetDisposition = "infer" - } - - rctx = rctx.LogWithFields(logrus.Fields{ - "ipfsContentId": ipfsContentId, - "server": server, - }) - - obj, err := ipfs_proxy.GetObject(ipfsContentId, rctx) - if err != nil { - rctx.Log.Error(err) - sentry.CaptureException(err) - return api.InternalServerError("unexpected error") - } - - return &r0.DownloadMediaResponse{ - ContentType: obj.ContentType, - Filename: obj.FileName, - SizeBytes: obj.SizeBytes, - Data: obj.Data, - TargetDisposition: targetDisposition, - } -} diff --git a/api/unstable/local_copy.go b/api/unstable/local_copy.go index 30d5f26fb20c2d29cf3ebb9aae86f04d19cc0e67..74166e60af6778a7cf350aaeea6bbdc54d2d3b2e 100644 --- a/api/unstable/local_copy.go +++ b/api/unstable/local_copy.go @@ -2,32 +2,36 @@ package unstable import ( "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/api/_apimeta" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/api/_routers" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "net/http" "strconv" - "github.com/gorilla/mux" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/api/r0" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/download_controller" "github.com/turt2live/matrix-media-repo/controllers/upload_controller" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) -func LocalCopy(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) interface{} { - params := mux.Vars(r) - - server := params["server"] - mediaId := params["mediaId"] +func LocalCopy(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} { + server := _routers.GetParam("server", r) + mediaId := _routers.GetParam("mediaId", r) allowRemote := r.URL.Query().Get("allow_remote") + if !_routers.ServerNameRegex.MatchString(server) { + return _responses.BadRequest("invalid server ID") + } + downloadRemote := true if allowRemote != "" { parsedFlag, err := strconv.ParseBool(allowRemote) if err != nil { - return api.InternalServerError("allow_remote flag does not appear to be a boolean") + return _responses.InternalServerError("allow_remote flag does not appear to be a boolean") } downloadRemote = parsedFlag } @@ -43,17 +47,17 @@ func LocalCopy(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) streamedMedia, err := download_controller.GetMedia(server, mediaId, downloadRemote, true, rctx) if err != nil { if err == common.ErrMediaNotFound { - return api.NotFoundError() + return _responses.NotFoundError() } else if err == common.ErrMediaTooLarge { - return api.RequestTooLarge() + return _responses.RequestTooLarge() } else if err == common.ErrMediaQuarantined { - return api.NotFoundError() // We lie for security + return _responses.NotFoundError() // We lie for security } rctx.Log.Error("Unexpected error locating media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } - defer cleanup.DumpAndCloseStream(streamedMedia.Stream) + defer stream_util.DumpAndCloseStream(streamedMedia.Stream) // Don't clone the media if it's already available on this domain if streamedMedia.KnownMedia.Origin == r.Host { @@ -64,7 +68,7 @@ func LocalCopy(r *http.Request, rctx rcontext.RequestContext, user api.UserInfo) if err != nil { rctx.Log.Error("Unexpected error storing media: " + err.Error()) sentry.CaptureException(err) - return api.InternalServerError("Unexpected Error") + return _responses.InternalServerError("Unexpected Error") } return &r0.MediaUploadedResponse{ContentUri: newMedia.MxcUri()} diff --git a/api/webserver.go b/api/webserver.go new file mode 100644 index 0000000000000000000000000000000000000000..ed9ae05c4ee4602fe468acc785dae4083662b21a --- /dev/null +++ b/api/webserver.go @@ -0,0 +1,90 @@ +package api + +import ( + "context" + "encoding/json" + "net" + "net/http" + "strconv" + "sync" + "time" + + "github.com/didip/tollbooth" + "github.com/getsentry/sentry-go" + sentryhttp "github.com/getsentry/sentry-go/http" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/api/_responses" + "github.com/turt2live/matrix-media-repo/common/config" +) + +var srv *http.Server +var waitGroup = &sync.WaitGroup{} +var reload = false + +func Init() *sync.WaitGroup { + address := net.JoinHostPort(config.Get().General.BindAddress, strconv.Itoa(config.Get().General.Port)) + + //defer func() { + // if err := recover(); err != nil { + // logrus.Fatal(err) + // } + //}() + + handler := buildRoutes() + + if config.Get().RateLimit.Enabled { + logrus.Debug("Enabling rate limit") + limiter := tollbooth.NewLimiter(0, nil) + limiter.SetIPLookups([]string{"X-Forwarded-For", "X-Real-IP", "RemoteAddr"}) + limiter.SetTokenBucketExpirationTTL(time.Hour) + limiter.SetBurst(config.Get().RateLimit.BurstCount) + limiter.SetMax(config.Get().RateLimit.RequestsPerSecond) + + b, _ := json.Marshal(_responses.RateLimitReached()) + limiter.SetMessage(string(b)) + limiter.SetMessageContentType("application/json") + + handler = tollbooth.LimitHandler(limiter, handler) + } + + // Note: we bind Sentry here to ensure we capture *everything* + sentryHandler := sentryhttp.New(sentryhttp.Options{}) + srv = &http.Server{Addr: address, Handler: sentryHandler.Handle(handler)} + reload = false + + go func() { + logrus.WithField("address", address).Info("Started up. Listening at http://" + address) + if err := srv.ListenAndServe(); err != http.ErrServerClosed { + sentry.CaptureException(err) + logrus.Fatal(err) + } + + // Only notify the main thread that we're done if we're actually done + srv = nil + if !reload { + waitGroup.Done() + } + }() + + return waitGroup +} + +func Reload() { + reload = true + + // Stop the server first + Stop() + + // Reload the web server, ignoring the wait group (because we don't care to wait here) + Init() +} + +func Stop() { + if srv != nil { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + if err := srv.Shutdown(ctx); err != nil { + panic(err) + } + } +} diff --git a/api/webserver/debug/pprof.go b/api/webserver/debug/pprof.go index 0635b96b019e1e54f33fd5a9194ffd1aea0db9a1..ba22f0abf7ad55990147060faca84c210c62f615 100644 --- a/api/webserver/debug/pprof.go +++ b/api/webserver/debug/pprof.go @@ -4,36 +4,50 @@ import ( "encoding/json" "net/http" "net/http/pprof" + + "github.com/julienschmidt/httprouter" ) -func BindPprofEndpoints(httpMux *http.ServeMux, secret string) { - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/allocs", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/block", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/cmdline", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/goroutine", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/heap", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/mutex", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/profile", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/threadcreate", pprofServe(pprof.Index, secret)) - httpMux.HandleFunc("/_matrix/media/unstable/io.t2bot/debug/pprof/trace", pprofServe(pprof.Index, secret)) +func BindPprofEndpoints(httpMux *httprouter.Router, secret string) { + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/allocs", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/block", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/cmdline", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/goroutine", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/heap", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/mutex", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/profile", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/threadcreate", pprofServe(pprof.Index, secret)) + httpMux.Handler("GET", "/_matrix/media/unstable/io.t2bot/debug/pprof/trace", pprofServe(pprof.Index, secret)) } -func pprofServe(fn func(http.ResponseWriter, *http.Request), secret string) func(http.ResponseWriter, *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - auth := r.Header.Get("Authorization") - if auth != ("Bearer " + secret) { - // Order is important: Set headers before sending responses - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - w.WriteHeader(http.StatusUnauthorized) - - encoder := json.NewEncoder(w) - encoder.Encode(&map[string]bool{"success": false}) - return - } - - // otherwise authed fine - r.URL.Path = r.URL.Path[len("/_matrix/media/unstable/io.t2bot"):] - fn(w, r) +type generatorFn = func(w http.ResponseWriter, r *http.Request) + +type requestContainer struct { + secret string + fn generatorFn +} + +func pprofServe(fn generatorFn, secret string) http.Handler { + return &requestContainer{ + secret: secret, + fn: fn, } } + +func (c *requestContainer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + auth := r.Header.Get("Authorization") + if auth != ("Bearer " + c.secret) { + // Order is important: Set headers before sending responses + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusUnauthorized) + + encoder := json.NewEncoder(w) + _ = encoder.Encode(&map[string]bool{"success": false}) + return + } + + // otherwise authed fine + r.URL.Path = r.URL.Path[len("/_matrix/media/unstable/io.t2bot"):] + c.fn(w, r) +} diff --git a/api/webserver/request_counter.go b/api/webserver/request_counter.go deleted file mode 100644 index bc411c58b61f74484015d05f9d1dec2f043fd8c6..0000000000000000000000000000000000000000 --- a/api/webserver/request_counter.go +++ /dev/null @@ -1,14 +0,0 @@ -package webserver - -import "strconv" - -type requestCounter struct { - lastId uint64 -} - -func (c *requestCounter) GetNextId() string { - strId := strconv.FormatUint(c.lastId, 10) - c.lastId = c.lastId + 1 - - return "REQ-" + strId -} diff --git a/api/webserver/route_handler.go b/api/webserver/route_handler.go deleted file mode 100644 index b67cf515ed06aed5c42828dee6998d8a4b60fe80..0000000000000000000000000000000000000000 --- a/api/webserver/route_handler.go +++ /dev/null @@ -1,402 +0,0 @@ -package webserver - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "math" - "mime" - "net" - "net/http" - "net/url" - "strconv" - "strings" - - "github.com/getsentry/sentry-go" - - "github.com/alioygur/is" - "github.com/prometheus/client_golang/prometheus" - "github.com/sebest/xff" - "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" - "github.com/turt2live/matrix-media-repo/api/r0" - "github.com/turt2live/matrix-media-repo/common" - "github.com/turt2live/matrix-media-repo/common/config" - "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/metrics" - "github.com/turt2live/matrix-media-repo/util" -) - -type handler struct { - h func(r *http.Request, ctx rcontext.RequestContext) interface{} - action string - reqCounter *requestCounter - ignoreHost bool -} - -func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - isUsingForwardedHost := false - if r.Header.Get("X-Forwarded-Host") != "" && config.Get().General.UseForwardedHost { - r.Host = r.Header.Get("X-Forwarded-Host") - isUsingForwardedHost = true - } - r.Host = strings.Split(r.Host, ":")[0] - - var raddr string - if config.Get().General.TrustAnyForward { - raddr = r.Header.Get("X-Forwarded-For") - } else { - raddr = xff.GetRemoteAddr(r) - } - if raddr == "" { - raddr = r.RemoteAddr - } - - host, _, err := net.SplitHostPort(raddr) - if err != nil { - logrus.Error(err) - sentry.CaptureException(err) - host = raddr - } - r.RemoteAddr = host - - contextLog := logrus.WithFields(logrus.Fields{ - "method": r.Method, - "host": r.Host, - "usingForwardedHost": isUsingForwardedHost, - "resource": r.URL.Path, - "contentType": r.Header.Get("Content-Type"), - "contentLength": r.ContentLength, - "queryString": util.GetLogSafeQueryString(r), - "requestId": h.reqCounter.GetNextId(), - "remoteAddr": r.RemoteAddr, - }) - contextLog.Info("Received request") - - // Send CORS and other basic headers - w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization") - w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Content-Security-Policy", "sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; media-src 'self'; object-src 'self';") - w.Header().Set("Cross-Origin-Resource-Policy", "cross-origin") - w.Header().Set("X-Content-Security-Policy", "sandbox;") - w.Header().Set("X-Robots-Tag", "noindex, nofollow, noarchive, noimageindex") - w.Header().Set("Server", "matrix-media-repo") - - // Process response - var res interface{} = api.AuthFailed() - var rctx rcontext.RequestContext - if util.IsServerOurs(r.Host) || h.ignoreHost { - contextLog.Info("Host is valid - processing request") - cfg := config.GetDomain(r.Host) - if h.ignoreHost { - dc := config.DomainConfigFrom(*config.Get()) - cfg = &dc - } - - // Build a context that can be used throughout the remainder of the app - // This is kinda annoying, but it's better than trying to pass our own - // thing throughout the layers. - ctx := r.Context() - ctx = context.WithValue(ctx, "mr.logger", contextLog) - ctx = context.WithValue(ctx, "mr.serverConfig", cfg) - ctx = context.WithValue(ctx, "mr.request", r) - rctx = rcontext.RequestContext{Context: ctx, Log: contextLog, Config: *cfg, Request: r} - r = r.WithContext(rctx) - - metrics.HttpRequests.With(prometheus.Labels{ - "host": r.Host, - "action": h.action, - "method": r.Method, - }).Inc() - res = h.h(r, rctx) - if res == nil { - res = &api.EmptyResponse{} - } - } else { - metrics.InvalidHttpRequests.With(prometheus.Labels{ - "action": h.action, - "method": r.Method, - }).Inc() - contextLog.Warn("The server name provided in the Host header is not configured, or the request was made directly to the media repo instead of through your reverse proxy. This request is being rejected.") - } - if res == nil { - res = api.InternalServerError("Error processing response") - } - - switch result := res.(type) { - case *api.DoNotCacheResponse: - res = result.Payload - break - } - - htmlRes, isHtml := res.(*api.HtmlResponse) - if isHtml { - contextLog.Info(fmt.Sprintf("Replying with result: %T %+v", res, fmt.Sprintf("<%d chars of html>", len(htmlRes.HTML)))) - } else { - contextLog.Info(fmt.Sprintf("Replying with result: %T %+v", res, res)) - } - - statusCode := http.StatusOK - switch result := res.(type) { - case *api.ErrorResponse: - switch result.InternalCode { - case common.ErrCodeUnknownToken: - statusCode = http.StatusUnauthorized - break - case common.ErrCodeNotFound: - statusCode = http.StatusNotFound - break - case common.ErrCodeMediaTooLarge: - statusCode = http.StatusRequestEntityTooLarge - break - case common.ErrCodeBadRequest: - statusCode = http.StatusBadRequest - break - case common.ErrCodeMethodNotAllowed: - statusCode = http.StatusMethodNotAllowed - break - case common.ErrCodeForbidden: - statusCode = http.StatusForbidden - break - default: // Treat as unknown (a generic server error) - statusCode = http.StatusInternalServerError - break - } - break - case *r0.DownloadMediaResponse: - // XXX: This range parsing isn't perfect, but works fine enough for now - rangeStart := int64(0) - rangeEnd := int64(0) - grabBytes := int64(0) - doRange := false - if r.Header.Get("Range") != "" && result.SizeBytes > 0 && rctx.Request != nil && config.Get().Redis.Enabled { - rnge := r.Header.Get("Range") - if !strings.HasPrefix(rnge, "bytes=") { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Improper range units") - break - } - if !strings.Contains(rnge, ",") && !strings.HasPrefix(rnge, "bytes=-") { - parts := strings.Split(rnge[len("bytes="):], "-") - if len(parts) <= 2 { - rstart, err := strconv.ParseInt(parts[0], 10, 64) - if err != nil { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Improper start of range") - break - } - - if rstart < 0 { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Improper start of range: negative") - break - } - - rend := int64(-1) - if len(parts) > 1 && parts[1] != "" { - rend, err = strconv.ParseInt(parts[1], 10, 64) - if err != nil { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Improper end of range") - break - } - - if rend < 1 { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Improper end of range: negative") - break - } - - if rend >= result.SizeBytes { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Improper end of range: out of bounds") - break - } - - if rend <= rstart { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Start must be before end") - break - } - - if (rstart + rend) >= result.SizeBytes { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Range too large") - break - } - - grabBytes = rend - rstart - } else { - add := int64(10485760) // 10mb default - if rctx.Config.Downloads.DefaultRangeChunkSizeBytes > 0 { - add = rctx.Config.Downloads.DefaultRangeChunkSizeBytes - } - rend = int64(math.Min(float64(rstart+add), float64(result.SizeBytes-1))) - grabBytes = (rend - rstart) + 1 - } - - rangeStart = rstart - rangeEnd = rend - - if (rangeEnd-rangeStart) <= 0 || grabBytes <= 0 { - statusCode = http.StatusRequestedRangeNotSatisfiable - res = api.BadRequest("Range invalid at last pass") - break - } - - doRange = true - } - } - } - - metrics.HttpResponses.With(prometheus.Labels{ - "host": r.Host, - "action": h.action, - "method": r.Method, - "statusCode": strconv.Itoa(http.StatusOK), - }).Inc() - - contentType := result.ContentType - mediaType, params, err := mime.ParseMediaType(result.ContentType) - if err != nil { - sentry.CaptureException(err) - contextLog.Warn("Failed to parse content type header for media on reply: " + err.Error()) - } else { - // TODO: Maybe we only strip the charset from images? Is it valid to have the param on other types? - if !strings.HasPrefix(mediaType, "text/") && mediaType != "application/json" { - delete(params, "charset") - } - contentType = mime.FormatMediaType(mediaType, params) - } - - w.Header().Set("Cache-Control", "private, max-age=259200") // 3 days - w.Header().Set("Content-Type", contentType) - if result.SizeBytes > 0 { - if config.Get().Redis.Enabled { - w.Header().Set("Accept-Ranges", "bytes") - } - w.Header().Set("Content-Length", fmt.Sprint(result.SizeBytes)) - } - disposition := result.TargetDisposition - if disposition == "" { - disposition = "inline" - } else if disposition == "infer" { - if result.ContentType == "" { - disposition = "attachment" - } else { - if util.HasAnyPrefix(result.ContentType, []string{"image/", "audio/", "video/", "text/plain"}) { - disposition = "inline" - } else { - disposition = "attachment" - } - } - } - fname := result.Filename - if fname == "" { - exts, err := mime.ExtensionsByType(result.ContentType) - if err != nil { - exts = nil - contextLog.Warn("Unexpected error inferring file extension: " + err.Error()) - sentry.CaptureException(err) - } - ext := "" - if exts != nil && len(exts) > 0 { - ext = exts[0] - } - fname = "file" + ext - } - if is.ASCII(result.Filename) { - w.Header().Set("Content-Disposition", disposition+"; filename="+url.QueryEscape(fname)) - } else { - w.Header().Set("Content-Disposition", disposition+"; filename*=utf-8''"+url.QueryEscape(fname)) - } - - defer result.Data.Close() - - if doRange { - _, err = io.CopyN(ioutil.Discard, result.Data, rangeStart) - if err != nil { - // Should only blow up this request - panic(err) - } - - expectedBytes := grabBytes - w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", rangeStart, rangeEnd, result.SizeBytes)) - w.Header().Set("Content-Length", fmt.Sprint(expectedBytes)) - w.WriteHeader(http.StatusPartialContent) - b, err := io.CopyN(w, result.Data, expectedBytes) - if err != nil { - // Should only blow up this request - panic(err) - } - - // Discard anything that remains - _, _ = io.Copy(ioutil.Discard, result.Data) - - if expectedBytes > 0 && b != expectedBytes { - // Should only blow up this request - panic(errors.New("mismatch transfer size")) - } - } else { - writeResponseData(w, result.Data, result.SizeBytes) - } - return // Prevent sending conflicting responses - case *r0.IdenticonResponse: - metrics.HttpResponses.With(prometheus.Labels{ - "host": r.Host, - "action": h.action, - "method": r.Method, - "statusCode": strconv.Itoa(http.StatusOK), - }).Inc() - w.Header().Set("Cache-Control", "private, max-age=604800") // 7 days - w.Header().Set("Content-Type", "image/png") - writeResponseData(w, result.Avatar, 0) - return // Prevent sending conflicting responses - case *api.HtmlResponse: - metrics.HttpResponses.With(prometheus.Labels{ - "host": r.Host, - "action": h.action, - "method": r.Method, - "statusCode": strconv.Itoa(http.StatusOK), - }).Inc() - w.Header().Set("Cache-Control", "private, max-age=259200") // 3 days - w.Header().Set("Content-Type", "text/html; charset=UTF-8") - w.Header().Set("Content-Security-Policy", "") // We're serving HTML, so take away the CSP - w.Header().Set("X-Content-Security-Policy", "") // We're serving HTML, so take away the CSP - io.Copy(w, bytes.NewBuffer([]byte(result.HTML))) - return - default: - break - } - - metrics.HttpResponses.With(prometheus.Labels{ - "host": r.Host, - "action": h.action, - "method": r.Method, - "statusCode": strconv.Itoa(statusCode), - }).Inc() - - // Order is important: Set headers before sending responses - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(statusCode) - - encoder := json.NewEncoder(w) - encoder.Encode(res) -} - -func writeResponseData(w http.ResponseWriter, s io.Reader, expectedBytes int64) { - b, err := io.Copy(w, s) - if err != nil { - // Should only blow up this request - panic(err) - } - if expectedBytes > 0 && b != expectedBytes { - // Should only blow up this request - panic(errors.New("mismatch transfer size")) - } -} diff --git a/api/webserver/webserver.go b/api/webserver/webserver.go deleted file mode 100644 index fb9c7dd4f2a866799877a72e65d32450d11d8263..0000000000000000000000000000000000000000 --- a/api/webserver/webserver.go +++ /dev/null @@ -1,251 +0,0 @@ -package webserver - -import ( - "context" - "encoding/json" - "github.com/getsentry/sentry-go" - sentryhttp "github.com/getsentry/sentry-go/http" - "net" - "net/http" - "os" - "strconv" - "strings" - "sync" - "time" - - "github.com/didip/tollbooth" - "github.com/gorilla/mux" - "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api" - "github.com/turt2live/matrix-media-repo/api/custom" - "github.com/turt2live/matrix-media-repo/api/features" - "github.com/turt2live/matrix-media-repo/api/r0" - "github.com/turt2live/matrix-media-repo/api/unstable" - "github.com/turt2live/matrix-media-repo/api/webserver/debug" - "github.com/turt2live/matrix-media-repo/common/config" -) - -type route struct { - method string - handler handler -} - -type definedRoute struct { - path string - route route -} - -var srv *http.Server -var waitGroup = &sync.WaitGroup{} -var reload = false - -func Init() *sync.WaitGroup { - rtr := mux.NewRouter() - counter := &requestCounter{} - - optionsHandler := handler{api.EmptyResponseHandler, "options_request", counter, false} - uploadHandler := handler{api.AccessTokenRequiredRoute(r0.UploadMedia), "upload", counter, false} - downloadHandler := handler{api.AccessTokenOptionalRoute(r0.DownloadMedia), "download", counter, false} - thumbnailHandler := handler{api.AccessTokenOptionalRoute(r0.ThumbnailMedia), "thumbnail", counter, false} - previewUrlHandler := handler{api.AccessTokenRequiredRoute(r0.PreviewUrl), "url_preview", counter, false} - identiconHandler := handler{api.AccessTokenOptionalRoute(r0.Identicon), "identicon", counter, false} - purgeRemote := handler{api.RepoAdminRoute(custom.PurgeRemoteMedia), "purge_remote_media", counter, false} - purgeOneHandler := handler{api.AccessTokenRequiredRoute(custom.PurgeIndividualRecord), "purge_individual_media", counter, false} - purgeQuarantinedHandler := handler{api.AccessTokenRequiredRoute(custom.PurgeQuarantined), "purge_quarantined", counter, false} - purgeUserMediaHandler := handler{api.AccessTokenRequiredRoute(custom.PurgeUserMedia), "purge_user_media", counter, false} - purgeRoomHandler := handler{api.AccessTokenRequiredRoute(custom.PurgeRoomMedia), "purge_room_media", counter, false} - purgeDomainHandler := handler{api.AccessTokenRequiredRoute(custom.PurgeDomainMedia), "purge_domain_media", counter, false} - purgeOldHandler := handler{api.RepoAdminRoute(custom.PurgeOldMedia), "purge_old_media", counter, false} - quarantineHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineMedia), "quarantine_media", counter, false} - quarantineRoomHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineRoomMedia), "quarantine_room", counter, false} - quarantineUserHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineUserMedia), "quarantine_user", counter, false} - quarantineDomainHandler := handler{api.AccessTokenRequiredRoute(custom.QuarantineDomainMedia), "quarantine_domain", counter, false} - localCopyHandler := handler{api.AccessTokenRequiredRoute(unstable.LocalCopy), "local_copy", counter, false} - infoHandler := handler{api.AccessTokenRequiredRoute(unstable.MediaInfo), "info", counter, false} - configHandler := handler{api.AccessTokenRequiredRoute(r0.PublicConfig), "config", counter, false} - storageEstimateHandler := handler{api.RepoAdminRoute(custom.GetDatastoreStorageEstimate), "get_storage_estimate", counter, false} - datastoreListHandler := handler{api.RepoAdminRoute(custom.GetDatastores), "list_datastores", counter, false} - dsTransferHandler := handler{api.RepoAdminRoute(custom.MigrateBetweenDatastores), "datastore_transfer", counter, false} - fedTestHandler := handler{api.RepoAdminRoute(custom.GetFederationInfo), "federation_test", counter, false} - healthzHandler := handler{api.AccessTokenOptionalRoute(custom.GetHealthz), "healthz", counter, true} - domainUsageHandler := handler{api.RepoAdminRoute(custom.GetDomainUsage), "domain_usage", counter, false} - userUsageHandler := handler{api.RepoAdminRoute(custom.GetUserUsage), "user_usage", counter, false} - uploadsUsageHandler := handler{api.RepoAdminRoute(custom.GetUploadsUsage), "uploads_usage", counter, false} - usersUsageStatsHandler := handler{api.AccessTokenRequiredRoute(custom.GetUsersUsageStats), "users_usage_stats", counter, false} - getBackgroundTaskHandler := handler{api.RepoAdminRoute(custom.GetTask), "get_background_task", counter, false} - listAllBackgroundTasksHandler := handler{api.RepoAdminRoute(custom.ListAllTasks), "list_all_background_tasks", counter, false} - listUnfinishedBackgroundTasksHandler := handler{api.RepoAdminRoute(custom.ListUnfinishedTasks), "list_unfinished_background_tasks", counter, false} - exportUserDataHandler := handler{api.AccessTokenRequiredRoute(custom.ExportUserData), "export_user_data", counter, false} - exportServerDataHandler := handler{api.AccessTokenRequiredRoute(custom.ExportServerData), "export_server_data", counter, false} - viewExportHandler := handler{api.AccessTokenOptionalRoute(custom.ViewExport), "view_export", counter, false} - getExportMetadataHandler := handler{api.AccessTokenOptionalRoute(custom.GetExportMetadata), "get_export_metadata", counter, false} - downloadExportPartHandler := handler{api.AccessTokenOptionalRoute(custom.DownloadExportPart), "download_export_part", counter, false} - deleteExportHandler := handler{api.AccessTokenOptionalRoute(custom.DeleteExport), "delete_export", counter, false} - startImportHandler := handler{api.RepoAdminRoute(custom.StartImport), "start_import", counter, false} - appendToImportHandler := handler{api.RepoAdminRoute(custom.AppendToImport), "append_to_import", counter, false} - stopImportHandler := handler{api.RepoAdminRoute(custom.StopImport), "stop_import", counter, false} - versionHandler := handler{api.AccessTokenOptionalRoute(custom.GetVersion), "get_version", counter, false} - ipfsDownloadHandler := handler{api.AccessTokenOptionalRoute(unstable.IPFSDownload), "ipfs_download", counter, false} - logoutHandler := handler{api.AccessTokenRequiredRoute(r0.Logout), "logout", counter, false} - logoutAllHandler := handler{api.AccessTokenRequiredRoute(r0.LogoutAll), "logout_all", counter, false} - getMediaAttrsHandler := handler{api.AccessTokenRequiredRoute(custom.GetAttributes), "get_media_attributes", counter, false} - setMediaAttrsHandler := handler{api.AccessTokenRequiredRoute(custom.SetAttributes), "set_media_attributes", counter, false} - - routes := make([]definedRoute, 0) - // r0 is typically clients and v1 is typically servers. v1 is deprecated. - // unstable is, well, unstable. unstable/io.t2bot.media is to comply with MSC2324 - // v3 is Matrix 1.1 stuff - versions := []string{"r0", "v1", "v3", "unstable", "unstable/io.t2bot.media"} - - // Things that don't need a version - routes = append(routes, definedRoute{"/_matrix/media/version", route{"GET", versionHandler}}) - - for _, version := range versions { - // Standard routes we have to handle - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/upload", route{"POST", uploadHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/download/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}/{filename:.+}", route{"GET", downloadHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/download/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"GET", downloadHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/thumbnail/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"GET", thumbnailHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/preview_url", route{"GET", previewUrlHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/identicon/{seed:.*}", route{"GET", identiconHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/config", route{"GET", configHandler}}) - routes = append(routes, definedRoute{"/_matrix/client/" + version + "/logout", route{"POST", logoutHandler}}) - routes = append(routes, definedRoute{"/_matrix/client/" + version + "/logout/all", route{"POST", logoutAllHandler}}) - - // Routes that we define but are not part of the spec (management) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/purge_remote", route{"POST", purgeRemote}}) // deprecated - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/purge/remote", route{"POST", purgeRemote}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/purge/quarantined", route{"POST", purgeQuarantinedHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/purge/user/{userId:[^/]+}", route{"POST", purgeUserMediaHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/purge/room/{roomId:[^/]+}", route{"POST", purgeRoomHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/purge/server/{serverName:[^/]+}", route{"POST", purgeDomainHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/purge/old", route{"POST", purgeOldHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/purge/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"POST", purgeOneHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/room/{roomId:[^/]+}/quarantine", route{"POST", quarantineRoomHandler}}) // deprecated - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/quarantine/room/{roomId:[^/]+}", route{"POST", quarantineRoomHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/quarantine/user/{userId:[^/]+}", route{"POST", quarantineUserHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/quarantine/server/{serverName:[^/]+}", route{"POST", quarantineDomainHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/quarantine/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"POST", quarantineHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/datastores/{datastoreId:[^/]+}/size_estimate", route{"GET", storageEstimateHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/datastores", route{"GET", datastoreListHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/datastores/{sourceDsId:[^/]+}/transfer_to/{targetDsId:[^/]+}", route{"POST", dsTransferHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/federation/test/{serverName:[a-zA-Z0-9.:\\-_]+}", route{"GET", fedTestHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/usage/{serverName:[a-zA-Z0-9.:\\-_]+}", route{"GET", domainUsageHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/usage/{serverName:[a-zA-Z0-9.:\\-_]+}/users", route{"GET", userUsageHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/usage/{serverName:[a-zA-Z0-9.:\\-_]+}/users-stats", route{"GET", usersUsageStatsHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/usage/{serverName:[a-zA-Z0-9.:\\-_]+}/uploads", route{"GET", uploadsUsageHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/tasks/{taskId:[0-9]+}", route{"GET", getBackgroundTaskHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/tasks/all", route{"GET", listAllBackgroundTasksHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/tasks/unfinished", route{"GET", listUnfinishedBackgroundTasksHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/user/{userId:[^/]+}/export", route{"POST", exportUserDataHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/server/{serverName:[^/]+}/export", route{"POST", exportServerDataHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/export/{exportId:[a-zA-Z0-9.:\\-_]+}/view", route{"GET", viewExportHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/export/{exportId:[a-zA-Z0-9.:\\-_]+}/metadata", route{"GET", getExportMetadataHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/export/{exportId:[a-zA-Z0-9.:\\-_]+}/part/{partId:[0-9]+}", route{"GET", downloadExportPartHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/export/{exportId:[a-zA-Z0-9.:\\-_]+}/delete", route{"DELETE", deleteExportHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/import", route{"POST", startImportHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/import/{importId:[a-zA-Z0-9.:\\-_]+}/part", route{"POST", appendToImportHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/import/{importId:[a-zA-Z0-9.:\\-_]+}/close", route{"POST", stopImportHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/media/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}/attributes", route{"GET", getMediaAttrsHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/admin/media/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}/attributes/set", route{"POST", setMediaAttrsHandler}}) - - // Routes that we should handle but aren't in the media namespace (synapse compat) - routes = append(routes, definedRoute{"/_matrix/client/" + version + "/admin/purge_media_cache", route{"POST", purgeRemote}}) - routes = append(routes, definedRoute{"/_matrix/client/" + version + "/admin/quarantine_media/{roomId:[^/]+}", route{"POST", quarantineRoomHandler}}) - - if strings.Index(version, "unstable") == 0 { - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/local_copy/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"GET", localCopyHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/info/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"GET", infoHandler}}) - routes = append(routes, definedRoute{"/_matrix/media/" + version + "/download/{server:[a-zA-Z0-9.:\\-_]+}/{mediaId:[^/]+}", route{"DELETE", purgeOneHandler}}) - } - } - - if config.Get().Features.IPFS.Enabled { - routes = append(routes, definedRoute{features.IPFSDownloadRoute, route{"GET", ipfsDownloadHandler}}) - routes = append(routes, definedRoute{features.IPFSLiveDownloadRouteR0, route{"GET", ipfsDownloadHandler}}) - routes = append(routes, definedRoute{features.IPFSLiveDownloadRouteV1, route{"GET", ipfsDownloadHandler}}) - routes = append(routes, definedRoute{features.IPFSLiveDownloadRouteUnstable, route{"GET", ipfsDownloadHandler}}) - } - - for _, def := range routes { - logrus.Info("Registering route: " + def.route.method + " " + def.path) - rtr.Handle(def.path, def.route.handler).Methods(def.route.method) - rtr.Handle(def.path, optionsHandler).Methods("OPTIONS") - - // This is a hack to a ensure that trailing slashes also match the routes correctly - rtr.Handle(def.path+"/", def.route.handler).Methods(def.route.method) - rtr.Handle(def.path+"/", optionsHandler).Methods("OPTIONS") - } - - // Health check endpoints - rtr.Handle("/healthz", healthzHandler).Methods("OPTIONS", "GET", "HEAD") - - rtr.NotFoundHandler = handler{api.NotFoundHandler, "not_found", counter, true} - rtr.MethodNotAllowedHandler = handler{api.MethodNotAllowedHandler, "method_not_allowed", counter, true} - - var handler http.Handler = rtr - if config.Get().RateLimit.Enabled { - logrus.Info("Enabling rate limit") - limiter := tollbooth.NewLimiter(0, nil) - limiter.SetIPLookups([]string{"X-Forwarded-For", "X-Real-IP", "RemoteAddr"}) - limiter.SetTokenBucketExpirationTTL(time.Hour) - limiter.SetBurst(config.Get().RateLimit.BurstCount) - limiter.SetMax(config.Get().RateLimit.RequestsPerSecond) - - b, _ := json.Marshal(api.RateLimitReached()) - limiter.SetMessage(string(b)) - limiter.SetMessageContentType("application/json") - - handler = tollbooth.LimitHandler(limiter, rtr) - } - - address := net.JoinHostPort(config.Get().General.BindAddress, strconv.Itoa(config.Get().General.Port)) - httpMux := http.NewServeMux() - httpMux.Handle("/", handler) - - pprofSecret := os.Getenv("MEDIA_PPROF_SECRET_KEY") - if pprofSecret != "" { - logrus.Warn("Enabling pprof endpoints") - debug.BindPprofEndpoints(httpMux, pprofSecret) - } - - sentryHandler := sentryhttp.New(sentryhttp.Options{}) - srv = &http.Server{Addr: address, Handler: sentryHandler.Handle(httpMux)} - reload = false - - go func() { - logrus.WithField("address", address).Info("Started up. Listening at http://" + address) - if err := srv.ListenAndServe(); err != http.ErrServerClosed { - sentry.CaptureException(err) - logrus.Fatal(err) - } - - // Only notify the main thread that we're done if we're actually done - srv = nil - if !reload { - waitGroup.Done() - } - }() - - return waitGroup -} - -func Reload() { - reload = true - - // Stop the server first - Stop() - - // Reload the web server, ignoring the wait group (because we don't care to wait here) - Init() -} - -func Stop() { - if srv != nil { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - if err := srv.Shutdown(ctx); err != nil { - panic(err) - } - } -} diff --git a/archival/v2_export.go b/archival/v2_export.go index f1ce9ca6d9196e743daea95612ea8bf88099dc66..0e504fe65dacbe29bbd0bde9055cb9d3225efb1a 100644 --- a/archival/v2_export.go +++ b/archival/v2_export.go @@ -15,6 +15,7 @@ import ( "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/templating" "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) type V2ArchiveWriter interface { @@ -49,7 +50,7 @@ func NewV2Export(exportId string, entity string, partSize int64, writer V2Archiv entity: entity, writer: writer, partSize: partSize, - ctx: ctx, + ctx: ctx, indexModel: &templating.ExportIndexModel{ Entity: entity, ExportID: exportId, @@ -91,7 +92,7 @@ func (e *V2ArchiveExport) persistTar() error { archiver.Name = "export-manifest.tar" } - if _, err := io.Copy(archiver, util.ClonedBufReader(*e.currentTarBytes)); err != nil { + if _, err := io.Copy(archiver, stream_util.ClonedBufReader(*e.currentTarBytes)); err != nil { return err } _ = archiver.Close() diff --git a/cluster/idgen.go b/cluster/idgen.go new file mode 100644 index 0000000000000000000000000000000000000000..e74c2e847b4cb335484a096dd98868ec750992ec --- /dev/null +++ b/cluster/idgen.go @@ -0,0 +1,41 @@ +package cluster + +import ( + "errors" + "fmt" + "io/ioutil" + "net/http" + "time" + + "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/stream_util" +) + +func GetId() (string, error) { + req, err := http.NewRequest("GET", util.MakeUrl(config.Get().Cluster.IDGenerator.Location, "/v1/id"), nil) + if err != nil { + return "", err + } + + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", config.Get().Cluster.IDGenerator.Secret)) + + client := &http.Client{ + Timeout: 1 * time.Second, // the server should be fast (much faster than this) + } + res, err := client.Do(req) + if err != nil { + return "", err + } + defer stream_util.DumpAndCloseStream(res.Body) + + contents, err := ioutil.ReadAll(res.Body) + if err != nil { + return "", err + } + if res.StatusCode != http.StatusOK { + return "", errors.New(fmt.Sprintf("unexpected status code from ID generator: %d", res.StatusCode)) + } + + return string(contents), nil +} diff --git a/cmd/export_synapse_for_import/main.go b/cmd/export_synapse_for_import/main.go index 1a9cb49f6675b63777002411458e907b24914942..8b5e6546dfeb889050124660b344d20288293ac4 100644 --- a/cmd/export_synapse_for_import/main.go +++ b/cmd/export_synapse_for_import/main.go @@ -19,6 +19,7 @@ import ( "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/synapse" "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/stream_util" "golang.org/x/crypto/ssh/terminal" ) @@ -126,7 +127,7 @@ func main() { _ = f.Close() temp := bytes.NewBuffer(d.Bytes()) - sha256, err := util.GetSha256HashOfStream(ioutil.NopCloser(temp)) + sha256, err := stream_util.GetSha256HashOfStream(ioutil.NopCloser(temp)) if err != nil { logrus.Fatal(err) } diff --git a/cmd/gdpr_export/main.go b/cmd/gdpr_export/main.go index 4b0e4bfad049caf72a8d0fa7785abfeeead17af1..0b5887e06dec24d228750797c8d30c79028880d5 100644 --- a/cmd/gdpr_export/main.go +++ b/cmd/gdpr_export/main.go @@ -17,7 +17,7 @@ import ( "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/storage/datastore" "github.com/turt2live/matrix-media-repo/types" - "github.com/turt2live/matrix-media-repo/util/cleanup" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) func main() { @@ -123,8 +123,8 @@ func main() { if err != nil { panic(err) } - cleanup.DumpAndCloseStream(f) - cleanup.DumpAndCloseStream(s) + stream_util.DumpAndCloseStream(f) + stream_util.DumpAndCloseStream(s) } logrus.Info("Deleting export now that it has been dumped") diff --git a/cmd/import_synapse/main.go b/cmd/import_synapse/main.go index 3c97b89c54404beae545d8c6a6f986fbeedd7175..4c8b246a6f40dcc8ac96b5b44dce3f53f115e6c4 100644 --- a/cmd/import_synapse/main.go +++ b/cmd/import_synapse/main.go @@ -22,7 +22,7 @@ import ( "github.com/turt2live/matrix-media-repo/controllers/upload_controller" "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/synapse" - "github.com/turt2live/matrix-media-repo/util/cleanup" + "github.com/turt2live/matrix-media-repo/util/stream_util" "golang.org/x/crypto/ssh/terminal" ) @@ -159,7 +159,7 @@ func fetchMedia(req interface{}) interface{} { logrus.Error(err.Error()) return nil } - defer cleanup.DumpAndCloseStream(body) + defer stream_util.DumpAndCloseStream(body) _, err = upload_controller.StoreDirect(nil, body, -1, record.ContentType, record.UploadName, record.UserId, payload.serverName, record.MediaId, common.KindLocalMedia, ctx, false) if err != nil { diff --git a/cmd/media_repo/main.go b/cmd/media_repo/main.go index ba828cb814e150e39583be0a5b5503ecd4a62939..970b1f8244f947e5be0725fb71732c8c1876e45f 100644 --- a/cmd/media_repo/main.go +++ b/cmd/media_repo/main.go @@ -3,9 +3,13 @@ package main import ( "flag" "fmt" + "os" + "os/signal" + "time" + "github.com/getsentry/sentry-go" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/api/webserver" + "github.com/turt2live/matrix-media-repo/api" "github.com/turt2live/matrix-media-repo/common/assets" "github.com/turt2live/matrix-media-repo/common/config" "github.com/turt2live/matrix-media-repo/common/logging" @@ -14,9 +18,6 @@ import ( "github.com/turt2live/matrix-media-repo/internal_cache" "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/tasks" - "os" - "os/signal" - "time" ) func main() { @@ -90,7 +91,7 @@ func main() { logrus.Info("Starting media repository...") metrics.Init() - web := webserver.Init() + web := api.Init() // Set up a function to stop everything stopAllButWeb := func() { @@ -117,7 +118,7 @@ func main() { stopAllButWeb() logrus.Info("Stopping web server...") - webserver.Stop() + api.Stop() }() // Wait for the web server to exit nicely diff --git a/cmd/media_repo/reloads.go b/cmd/media_repo/reloads.go index a51a1c28dd7912016ea8a727673743cb72dec0e8..79cb16f4be101461585f25e38ab93905ab148b47 100644 --- a/cmd/media_repo/reloads.go +++ b/cmd/media_repo/reloads.go @@ -1,12 +1,11 @@ package main import ( - "github.com/turt2live/matrix-media-repo/api/auth_cache" - "github.com/turt2live/matrix-media-repo/api/webserver" + "github.com/turt2live/matrix-media-repo/api" + "github.com/turt2live/matrix-media-repo/api/_auth_cache" "github.com/turt2live/matrix-media-repo/common/globals" "github.com/turt2live/matrix-media-repo/common/runtime" "github.com/turt2live/matrix-media-repo/internal_cache" - "github.com/turt2live/matrix-media-repo/ipfs_proxy" "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/plugins" "github.com/turt2live/matrix-media-repo/storage" @@ -19,7 +18,6 @@ func setupReloads() { reloadDatabaseOnChan(globals.DatabaseReloadChan) reloadDatastoresOnChan(globals.DatastoresReloadChan) reloadRecurringTasksOnChan(globals.RecurringTasksReloadChan) - reloadIpfsOnChan(globals.IPFSReloadChan) reloadAccessTokensOnChan(globals.AccessTokenReloadChan) reloadCacheOnChan(globals.CacheReplaceChan) reloadPluginsOnChan(globals.PluginReloadChan) @@ -33,7 +31,6 @@ func stopReloads() { globals.DatastoresReloadChan <- false globals.AccessTokenReloadChan <- false globals.RecurringTasksReloadChan <- false - globals.IPFSReloadChan <- false globals.CacheReplaceChan <- false globals.PluginReloadChan <- false } @@ -44,7 +41,7 @@ func reloadWebOnChan(reloadChan chan bool) { for { shouldReload := <-reloadChan if shouldReload { - webserver.Reload() + api.Reload() } else { return // received stop } @@ -111,27 +108,13 @@ func reloadRecurringTasksOnChan(reloadChan chan bool) { }() } -func reloadIpfsOnChan(reloadChan chan bool) { - go func() { - defer close(reloadChan) - for { - shouldReload := <-reloadChan - if shouldReload { - ipfs_proxy.Reload() - } else { - ipfs_proxy.Stop() - } - } - }() -} - func reloadAccessTokensOnChan(reloadChan chan bool) { go func() { defer close(reloadChan) for { shouldReload := <-reloadChan if shouldReload { - auth_cache.FlushCache() + _auth_cache.FlushCache() } } }() diff --git a/cmd/service_idgen/main.go b/cmd/service_idgen/main.go new file mode 100644 index 0000000000000000000000000000000000000000..c7b2b1dfe71492beb45df1feebe789e722b52412 --- /dev/null +++ b/cmd/service_idgen/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "flag" + "fmt" + "github.com/bwmarrin/snowflake" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/util" + "net/http" + "os" + "strconv" +) + +func main() { + machineId := flag.Int("machine", getIdFromEnv(), "The machine ID. 0-1023 (inclusive)") + secret := flag.String("secret", getValFromEnv("API_SECRET", ""), "The API secret to require on requests") + bind := flag.String("bind", getValFromEnv("API_BIND", ":8090"), "Where to bind the API to") + flag.Parse() + + node, err := snowflake.NewNode(int64(*machineId)) + if err != nil { + panic(err) + } + + fmt.Printf("Running as machine %d\n", *machineId) + + expectedSecret := fmt.Sprintf("Bearer %s", *secret) + + http.HandleFunc("/v1/id", func(w http.ResponseWriter, req *http.Request) { + if req.Header.Get("Authorization") != expectedSecret { + w.WriteHeader(http.StatusForbidden) + return + } + + // Generate a random string to pad out the returned ID + r, err := util.GenerateRandomString(32) + if err != nil { + logrus.Error(err) + w.WriteHeader(500) + return + } + s := r + node.Generate().String() + + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusOK) + _, err = w.Write([]byte(s)) + if err != nil { + fmt.Println(err) + return + } + }) + + err = http.ListenAndServe(*bind, nil) + if err != nil { + panic(err) + } +} + +func getIdFromEnv() int { + if val, ok := os.LookupEnv("MACHINE_ID"); ok { + if i, err := strconv.Atoi(val); err == nil { + return i + } + } + return 0 +} + +func getValFromEnv(key string, def string) string { + if val, ok := os.LookupEnv(key); ok { + return val + } + return def +} diff --git a/common/config/access.go b/common/config/access.go index 9b4c80ce5da7c279af24917e548d4a887cfdec55..06f0e6560d10a189f549d9a64b1da7105663d4dd 100644 --- a/common/config/access.go +++ b/common/config/access.go @@ -9,7 +9,7 @@ import ( "sync" "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/util/cleanup" + "github.com/turt2live/matrix-media-repo/util/stream_util" "gopkg.in/yaml.v3" ) @@ -105,7 +105,7 @@ func reloadConfig() (*MainRepoConfig, map[string]*DomainRepoConfig, error) { if err != nil { return nil, nil, err } - defer cleanup.DumpAndCloseStream(f) + defer stream_util.DumpAndCloseStream(f) buffer, err := ioutil.ReadAll(f) if err != nil { diff --git a/common/config/conf_main.go b/common/config/conf_main.go index ecc508d093b6ba79d36f8e1a95011ae18e541d90..0353e781c08b21e7a2e2c592094973be27b22941 100644 --- a/common/config/conf_main.go +++ b/common/config/conf_main.go @@ -16,6 +16,7 @@ type MainRepoConfig struct { Plugins []PluginConfig `yaml:"plugins,flow"` Sentry SentryConfig `yaml:"sentry"` Redis RedisConfig `yaml:"redis"` + Cluster ClusterConfig `yaml:"cluster"` } func NewDefaultMainConfig() MainRepoConfig { @@ -134,5 +135,11 @@ func NewDefaultMainConfig() MainRepoConfig { Enabled: false, Shards: []RedisShardConfig{}, }, + Cluster: ClusterConfig{ + IDGenerator: IDGeneratorConfig{ + Location: "", + Secret: "", + }, + }, } } diff --git a/common/config/conf_min_shared.go b/common/config/conf_min_shared.go index e43dffc23c1e9a03299e1886979317e5eb9e3837..09eb8212303ad8305105b130374d00606d30ebea 100644 --- a/common/config/conf_min_shared.go +++ b/common/config/conf_min_shared.go @@ -53,13 +53,6 @@ func NewDefaultMinimumRepoConfig() MinimumRepoConfig { YComponents: 3, Punch: 1, }, - IPFS: IPFSConfig{ - Enabled: false, - Daemon: IPFSDaemonConfig{ - Enabled: true, - RepoPath: "./ipfs", - }, - }, }, AccessTokens: AccessTokenConfig{ MaxCacheTimeSeconds: 0, diff --git a/common/config/models_domain.go b/common/config/models_domain.go index 32427247184a271f42c81ed4c3ed1af068eb2036..0c3fc55b819bf973b91342627b84e85cfae535c5 100644 --- a/common/config/models_domain.go +++ b/common/config/models_domain.go @@ -88,7 +88,6 @@ type TimeoutsConfig struct { type FeatureConfig struct { MSC2448Blurhash MSC2448Config `yaml:"MSC2448"` - IPFS IPFSConfig `yaml:"IPFS"` Redis RedisConfig `yaml:"redis"` } @@ -103,16 +102,6 @@ type MSC2448Config struct { Punch int `yaml:"punch"` } -type IPFSConfig struct { - Enabled bool `yaml:"enabled"` - Daemon IPFSDaemonConfig `yaml:"builtInDaemon"` -} - -type IPFSDaemonConfig struct { - Enabled bool `yaml:"enabled"` - RepoPath string `yaml:"repoPath"` -} - type AccessTokenConfig struct { MaxCacheTimeSeconds int `yaml:"maxCacheTimeSeconds"` UseAppservices bool `yaml:"useLocalAppserviceConfig"` diff --git a/common/config/models_main.go b/common/config/models_main.go index 084ff06cf2af6c005f35231b6727316b80993031..bde7479dd82ab2a4b56954f7b4b8086e76b3e655 100644 --- a/common/config/models_main.go +++ b/common/config/models_main.go @@ -89,3 +89,12 @@ type RedisShardConfig struct { Name string `yaml:"name"` Address string `yaml:"addr"` } + +type ClusterConfig struct { + IDGenerator IDGeneratorConfig `yaml:"idGenerator"` +} + +type IDGeneratorConfig struct { + Location string `yaml:"location"` + Secret string `yaml:"secret"` +} diff --git a/common/config/watch.go b/common/config/watch.go index 9d9d4b9442c3bb7e056f8b1c0d10ccacd4ffccb9..bf455c430cc0fddf9d6ec4ba5564ffa2cab13233 100644 --- a/common/config/watch.go +++ b/common/config/watch.go @@ -1,9 +1,10 @@ package config import ( - "github.com/getsentry/sentry-go" "time" + "github.com/getsentry/sentry-go" + "github.com/bep/debounce" "github.com/fsnotify/fsnotify" "github.com/sirupsen/logrus" @@ -92,13 +93,6 @@ func onFileChanged() { logrus.Warn("Log configuration changed - restart the media repo to apply changes") } - ipfsDaemonChange := configNew.Features.IPFS.Daemon.Enabled != configNow.Features.IPFS.Daemon.Enabled - ipfsDaemonPathChange := configNew.Features.IPFS.Daemon.RepoPath != configNow.Features.IPFS.Daemon.RepoPath - if ipfsDaemonChange || ipfsDaemonPathChange { - logrus.Warn("IPFS Daemon options changed - reloading") - globals.IPFSReloadChan <- true - } - redisEnabledChange := configNew.Features.Redis.Enabled != configNow.Features.Redis.Enabled redisShardsChange := hasRedisShardConfigChanged(configNew, configNow) if redisEnabledChange || redisShardsChange { @@ -125,9 +119,6 @@ func hasWebFeatureChanged(configNew *MainRepoConfig, configNow *MainRepoConfig) if configNew.Features.MSC2448Blurhash.Enabled != configNow.Features.MSC2448Blurhash.Enabled { return true } - if configNew.Features.IPFS.Enabled != configNow.Features.IPFS.Enabled { - return true - } return false } diff --git a/common/globals/reload.go b/common/globals/reload.go index 4bd8978e91c6e87177b7e3e5ebca14fd91422cab..ae2870d459c8382963c64725b4035f9d0f4fb829 100644 --- a/common/globals/reload.go +++ b/common/globals/reload.go @@ -5,7 +5,6 @@ var MetricsReloadChan = make(chan bool) var DatabaseReloadChan = make(chan bool) var DatastoresReloadChan = make(chan bool) var RecurringTasksReloadChan = make(chan bool) -var IPFSReloadChan = make(chan bool) var AccessTokenReloadChan = make(chan bool) var CacheReplaceChan = make(chan bool) var PluginReloadChan = make(chan bool) diff --git a/common/runtime/init.go b/common/runtime/init.go index 4d6a1c52154490712f289b822cbaa3df7f071eb5..4d27803068c645dc0f21a71cdda864fce64cac58 100644 --- a/common/runtime/init.go +++ b/common/runtime/init.go @@ -2,13 +2,13 @@ package runtime import ( "fmt" + "github.com/getsentry/sentry-go" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common/config" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/common/version" - "github.com/turt2live/matrix-media-repo/ipfs_proxy" "github.com/turt2live/matrix-media-repo/plugins" "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/storage/datastore" @@ -22,9 +22,6 @@ func RunStartupSequence() { LoadDatabase() LoadDatastores() plugins.ReloadPlugins() - - logrus.Info("Starting IPFS (if enabled)...") - ipfs_proxy.Reload() } func LoadDatabase() { diff --git a/config.sample.yaml b/config.sample.yaml index fa49e74f7e49e2c8678d85d78cee320d7c0d2314..9837491e6ecb6540a82693c56b88feca75ab0bdd 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -178,20 +178,6 @@ datastores: # See https://aws.amazon.com/s3/storage-classes/ for details; uncomment to use. #storageClass: STANDARD - # The media repo does support an IPFS datastore, but only if the IPFS feature is enabled. If - # the feature is not enabled, this will not work. Note that IPFS support is experimental at - # the moment and not recommended for general use. - # - # NOTE: Everything you upload to IPFS will be publicly accessible, even when the media repo - # puts authentication on the download endpoints. Only use this option for cases where you - # expect your media to be publicly accessible. - - type: ipfs - enabled: false # Enable this to use IPFS support - forKinds: ["local_media"] - # The IPFS datastore currently has no options. It will use the daemon or HTTP API configured - # in the IPFS section of your main config. - opts: {} - # Options for controlling archives. Archives are exports of a particular user's content for # the purpose of GDPR or moving media to a different server. archiving: @@ -544,24 +530,6 @@ featureSupport: # make the effect more subtle, larger values make it stronger. punch: 1 - # IPFS Support - # This is currently experimental and might not work at all. - IPFS: - # Whether or not IPFS support is enabled for use in the media repo. - enabled: false - - # Options for the built in IPFS daemon - builtInDaemon: - # Enable this to spawn an in-process IPFS node to use instead of a localhost - # HTTP agent. If this is disabled, the media repo will assume you have an HTTP - # IPFS agent running and accessible. Defaults to using a daemon (true). - enabled: true - - # If the Daemon is enabled, set this to the location where the IPFS files should - # be stored. If you're using Docker, this should be something like "/data/ipfs" - # so it can be mapped to a volume. - repoPath: "./ipfs" - # Support for redis as a cache mechanism # # Note: Enabling Redis support will mean that the existing cache mechanism will do nothing. @@ -597,4 +565,18 @@ sentry: environment: "" # Whether or not to turn on sentry's built in debugging. This will increase log output. - debug: false \ No newline at end of file + debug: false + +# Options for controlling clustering behaviour of the media repo. This requires an ID generator +# service in your infrastructure. +# +# For more information see https://docs.t2bot.io/matrix-media-repo/installing/environments/clustered.html +cluster: + # Options for accessing the ID generator service. + idGenerator: + # The secret being used by the ID generator service. Clustering is disabled unless this is set + # to a non-empty string. + secret: "" + + # The URL for where the ID generator service can be reached. + location: "http://localhost:8090" diff --git a/controllers/data_controller/export_controller.go b/controllers/data_controller/export_controller.go index 352cb7bf39c4e66e3141acf45252fcd42a01cd34..2b50affcbbb91b7376afd8e78f68da303b59e99f 100644 --- a/controllers/data_controller/export_controller.go +++ b/controllers/data_controller/export_controller.go @@ -7,10 +7,13 @@ import ( "context" "encoding/json" "fmt" - "github.com/getsentry/sentry-go" "io" "time" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/util/ids" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/dustin/go-humanize" "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" @@ -20,7 +23,6 @@ import ( "github.com/turt2live/matrix-media-repo/templating" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) type ManifestRecord struct { @@ -47,7 +49,7 @@ type Manifest struct { } func StartServerExport(serverName string, s3urls bool, includeData bool, ctx rcontext.RequestContext) (*types.BackgroundTask, string, error) { - exportId, err := util.GenerateRandomString(128) + exportId, err := ids.NewUniqueId() if err != nil { return nil, "", err } @@ -100,7 +102,7 @@ func StartServerExport(serverName string, s3urls bool, includeData bool, ctx rco } func StartUserExport(userId string, s3urls bool, includeData bool, ctx rcontext.RequestContext) (*types.BackgroundTask, string, error) { - exportId, err := util.GenerateRandomString(128) + exportId, err := ids.NewUniqueId() if err != nil { return nil, "", err } @@ -122,7 +124,7 @@ func StartUserExport(userId string, s3urls bool, includeData bool, ctx rcontext. ctx.Context = context.Background() db := storage.GetDatabase().GetMetadataStore(ctx) - ds, err := datastore.PickDatastore(common.KindArchives, ctx, ) + ds, err := datastore.PickDatastore(common.KindArchives, ctx) if err != nil { ctx.Log.Error(err) sentry.CaptureException(err) @@ -175,7 +177,7 @@ func compileArchive(exportId string, entityId string, archiveDs *datastore.Datas gzipBytes := bytes.Buffer{} archiver := gzip.NewWriter(&gzipBytes) archiver.Name = fmt.Sprintf("export-part-%d.tar", part) - _, err := io.Copy(archiver, util.BufferToStream(bytes.NewBuffer(currentTarBytes.Bytes()))) + _, err := io.Copy(archiver, stream_util.BufferToStream(bytes.NewBuffer(currentTarBytes.Bytes()))) if err != nil { return err } @@ -184,7 +186,7 @@ func compileArchive(exportId string, entityId string, archiveDs *datastore.Datas ctx.Log.Info("Uploading compressed tar file") buf := bytes.NewBuffer(gzipBytes.Bytes()) size := int64(buf.Len()) - obj, err := archiveDs.UploadFile(util.BufferToStream(buf), size, ctx) + obj, err := archiveDs.UploadFile(stream_util.BufferToStream(buf), size, ctx) if err != nil { return err } @@ -312,7 +314,7 @@ func compileArchive(exportId string, entityId string, archiveDs *datastore.Datas } ctx.Log.Info("Writing manifest") - err = putFile("manifest.json", int64(len(b)), time.Now(), util.BufferToStream(bytes.NewBuffer(b))) + err = putFile("manifest.json", int64(len(b)), time.Now(), stream_util.BufferToStream(bytes.NewBuffer(b))) if err != nil { ctx.Log.Error(err) sentry.CaptureException(err) @@ -334,7 +336,7 @@ func compileArchive(exportId string, entityId string, archiveDs *datastore.Datas sentry.CaptureException(err) return } - err = putFile("index.html", int64(html.Len()), time.Now(), util.BufferToStream(bytes.NewBuffer(html.Bytes()))) + err = putFile("index.html", int64(html.Len()), time.Now(), stream_util.BufferToStream(bytes.NewBuffer(html.Bytes()))) if err != nil { ctx.Log.Error(err) sentry.CaptureException(err) @@ -356,12 +358,12 @@ func compileArchive(exportId string, entityId string, archiveDs *datastore.Datas _, err = io.Copy(&b, s) if err != nil { ctx.Log.Error(err) - cleanup.DumpAndCloseStream(s) + stream_util.DumpAndCloseStream(s) sentry.CaptureException(err) continue } - cleanup.DumpAndCloseStream(s) - s = util.BufferToStream(bytes.NewBuffer(b.Bytes())) + stream_util.DumpAndCloseStream(s) + s = stream_util.BufferToStream(bytes.NewBuffer(b.Bytes())) ctx.Log.Info("Archiving ", m.MxcUri()) err = putFile(archivedName(m), m.SizeBytes, time.Unix(0, m.CreationTs*int64(time.Millisecond)), s) diff --git a/controllers/data_controller/import_controller.go b/controllers/data_controller/import_controller.go index c765fb2cd126b9c7603e4774bb040ce3b1c57336..57587dc207398e5a6a76a216828219dd192c125e 100644 --- a/controllers/data_controller/import_controller.go +++ b/controllers/data_controller/import_controller.go @@ -8,11 +8,14 @@ import ( "database/sql" "encoding/json" "errors" - "github.com/getsentry/sentry-go" "io" "net/http" "sync" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/util/ids" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/turt2live/matrix-media-repo/common" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/upload_controller" @@ -78,7 +81,7 @@ func StartImport(data io.Reader, ctx rcontext.RequestContext) (*types.Background return nil, "", err } - importId, err := util.GenerateRandomString(128) + importId, err := ids.NewUniqueId() if err != nil { return nil, "", err } @@ -335,7 +338,7 @@ func doImport(updateChannel chan *importUpdate, taskId int, importId string, ctx buf, found := fileMap[record.ArchivedName] if found { ctx.Log.Info("Using file from memory") - closer := util.BufferToStream(buf) + closer := stream_util.BufferToStream(buf) _, err := upload_controller.StoreDirect(nil, closer, record.SizeBytes, record.ContentType, record.FileName, userId, record.Origin, record.MediaId, kind, ctx, true) if err != nil { ctx.Log.Errorf("Error importing file: %s", err.Error()) diff --git a/controllers/download_controller/download_controller.go b/controllers/download_controller/download_controller.go index 4d7f354bccfbd1d6a124b3b238e46c96de9a020f..3c70c715a2eb13baa3091ba1b11d3ec5dda0c854 100644 --- a/controllers/download_controller/download_controller.go +++ b/controllers/download_controller/download_controller.go @@ -5,11 +5,13 @@ import ( "database/sql" "errors" "fmt" - "github.com/getsentry/sentry-go" "io" "io/ioutil" "time" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/disintegration/imaging" "github.com/patrickmn/go-cache" "github.com/turt2live/matrix-media-repo/common" @@ -21,7 +23,6 @@ import ( "github.com/turt2live/matrix-media-repo/storage/datastore" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) var localCache = cache.New(30*time.Second, 60*time.Second) @@ -70,7 +71,7 @@ func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia if media != nil { if media.Quarantined { ctx.Log.Warn("Quarantined media accessed") - defer cleanup.DumpAndCloseStream(minMedia.Stream) + defer stream_util.DumpAndCloseStream(minMedia.Stream) if ctx.Config.Quarantine.ReplaceDownloads { ctx.Log.Info("Replacing thumbnail with a quarantined one") @@ -84,7 +85,7 @@ func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia imaging.Encode(data, img, imaging.PNG) return &types.MinimalMedia{ // Lie about all the details - Stream: util.BufferToStream(data), + Stream: stream_util.BufferToStream(data), ContentType: "image/png", UploadName: "quarantine.png", SizeBytes: int64(data.Len()), @@ -131,7 +132,7 @@ func GetMedia(origin string, mediaId string, downloadRemote bool, blockForMedia rv := v.(*types.MinimalMedia) vals := make([]interface{}, 0) - streams := util.CloneReader(rv.Stream, count) + streams := stream_util.CloneReader(rv.Stream, count) for i := 0; i < count; i++ { if rv.KnownMedia != nil { diff --git a/controllers/download_controller/download_resource_handler.go b/controllers/download_controller/download_resource_handler.go index 35358ecdd260fe7253d829124454e7daed278cc9..cb592c1cd04fdfa10c660ea3874b028cf6832e43 100644 --- a/controllers/download_controller/download_resource_handler.go +++ b/controllers/download_controller/download_resource_handler.go @@ -2,8 +2,6 @@ package download_controller import ( "errors" - "github.com/getsentry/sentry-go" - "github.com/turt2live/matrix-media-repo/util" "io" "io/ioutil" "mime" @@ -11,6 +9,10 @@ import ( "sync" "time" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/djherbis/stream" "github.com/patrickmn/go-cache" "github.com/prometheus/client_golang/prometheus" @@ -22,7 +24,6 @@ import ( "github.com/turt2live/matrix-media-repo/matrix" "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/types" - "github.com/turt2live/matrix-media-repo/util/cleanup" "github.com/turt2live/matrix-media-repo/util/resource_handler" ) @@ -153,7 +154,7 @@ func downloadResourceWorkFn(request *resource_handler.WorkRequest) (resp *worker } persistFile := func(fileStream io.ReadCloser, r *workerDownloadResponse) *workerDownloadResponse { - defer cleanup.DumpAndCloseStream(fileStream) + defer stream_util.DumpAndCloseStream(fileStream) userId := upload_controller.NoApplicableUploadUser ms := stream.NewMemStream() diff --git a/controllers/info_controller/info_controller.go b/controllers/info_controller/info_controller.go index 281ec6063f277a49a0aecfad83c88ed15235cd63..98eb09699fd1aa1d15df2564dcf8884b69961054 100644 --- a/controllers/info_controller/info_controller.go +++ b/controllers/info_controller/info_controller.go @@ -10,7 +10,7 @@ import ( "github.com/turt2live/matrix-media-repo/controllers/download_controller" "github.com/turt2live/matrix-media-repo/storage" "github.com/turt2live/matrix-media-repo/types" - "github.com/turt2live/matrix-media-repo/util/cleanup" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) func GetOrCalculateBlurhash(media *types.Media, rctx rcontext.RequestContext) (string, error) { @@ -31,7 +31,7 @@ func GetOrCalculateBlurhash(media *types.Media, rctx rcontext.RequestContext) (s if err != nil { return "", err } - defer cleanup.DumpAndCloseStream(minMedia.Stream) + defer stream_util.DumpAndCloseStream(minMedia.Stream) // No cached blurhash: calculate one rctx.Log.Info("Decoding image for blurhash calculation") diff --git a/controllers/preview_controller/preview_resource_handler.go b/controllers/preview_controller/preview_resource_handler.go index 86c42b9d9d4e2a05a3760cf9771487a19ff7c01b..3230caa12be950f40f4d148ce1edeec185a3eea6 100644 --- a/controllers/preview_controller/preview_resource_handler.go +++ b/controllers/preview_controller/preview_resource_handler.go @@ -2,9 +2,11 @@ package preview_controller import ( "fmt" - "github.com/getsentry/sentry-go" "sync" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/disintegration/imaging" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common" @@ -17,7 +19,6 @@ import ( "github.com/turt2live/matrix-media-repo/storage/datastore" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" "github.com/turt2live/matrix-media-repo/util/resource_handler" ) @@ -143,7 +144,7 @@ func urlPreviewWorkFn(request *resource_handler.WorkRequest) (resp *urlPreviewRe ctx.Log.Warn("Non-fatal error streaming datastore file: " + err.Error()) sentry.CaptureException(err) } else { - defer cleanup.DumpAndCloseStream(mediaStream) + defer stream_util.DumpAndCloseStream(mediaStream) img, err := imaging.Decode(mediaStream) if err != nil { ctx.Log.Warn("Non-fatal error getting thumbnail dimensions: " + err.Error()) diff --git a/controllers/preview_controller/previewers/calculated_previewer.go b/controllers/preview_controller/previewers/calculated_previewer.go index d41f21c69b646178293135c9661ed642adab1bd1..a40672a38975e9984fd7cfd0125ab61ca95f8784 100644 --- a/controllers/preview_controller/previewers/calculated_previewer.go +++ b/controllers/preview_controller/previewers/calculated_previewer.go @@ -9,7 +9,7 @@ import ( "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/controllers/preview_controller/preview_types" "github.com/turt2live/matrix-media-repo/metrics" - "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) func GenerateCalculatedPreview(urlPayload *preview_types.UrlPayload, languageHeader string, ctx rcontext.RequestContext) (preview_types.PreviewResult, error) { @@ -26,7 +26,7 @@ func GenerateCalculatedPreview(urlPayload *preview_types.UrlPayload, languageHea return preview_types.PreviewResult{}, common.ErrMediaNotFound } - stream := util.BufferToStream(bytes2.NewBuffer(bytes)) + stream := stream_util.BufferToStream(bytes2.NewBuffer(bytes)) img := &preview_types.PreviewImage{ Data: stream, ContentType: contentType, diff --git a/controllers/preview_controller/previewers/http.go b/controllers/preview_controller/previewers/http.go index 7c6deb96104723cfc70acc0c61e457f6cf627806..d20ae455aef5aa334e65e8941a5db09575dc4641 100644 --- a/controllers/preview_controller/previewers/http.go +++ b/controllers/preview_controller/previewers/http.go @@ -18,7 +18,7 @@ import ( "github.com/turt2live/matrix-media-repo/controllers/preview_controller/acl" "github.com/turt2live/matrix-media-repo/controllers/preview_controller/preview_types" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) func doHttpGet(urlPayload *preview_types.UrlPayload, languageHeader string, ctx rcontext.RequestContext) (*http.Response, error) { @@ -149,7 +149,7 @@ func downloadRawContent(urlPayload *preview_types.UrlPayload, supportedTypes []s return nil, "", "", "", err } - defer cleanup.DumpAndCloseStream(resp.Body) + defer stream_util.DumpAndCloseStream(resp.Body) contentType := resp.Header.Get("Content-Type") for _, supportedType := range supportedTypes { diff --git a/controllers/thumbnail_controller/thumbnail_controller.go b/controllers/thumbnail_controller/thumbnail_controller.go index 9b5e1212b928ccb8aac8e87b02089a973f08e4fe..1898b994d364ed03341a0a062100985d238053ba 100644 --- a/controllers/thumbnail_controller/thumbnail_controller.go +++ b/controllers/thumbnail_controller/thumbnail_controller.go @@ -4,10 +4,12 @@ import ( "bytes" "database/sql" "fmt" - "github.com/getsentry/sentry-go" "io/ioutil" "time" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/disintegration/imaging" "github.com/patrickmn/go-cache" "github.com/pkg/errors" @@ -58,7 +60,7 @@ func GetThumbnail(origin string, mediaId string, desiredWidth int, desiredHeight data := &bytes.Buffer{} _ = imaging.Encode(data, img, imaging.PNG) return &types.StreamedThumbnail{ - Stream: util.BufferToStream(data), + Stream: stream_util.BufferToStream(data), Thumbnail: &types.Thumbnail{ // We lie about the details to ensure we keep our contract Width: img.Bounds().Max.X, @@ -165,7 +167,7 @@ func GetThumbnail(origin string, mediaId string, desiredWidth int, desiredHeight rv := v.(*types.StreamedThumbnail) vals := make([]interface{}, 0) - streams := util.CloneReader(rv.Stream, count) + streams := stream_util.CloneReader(rv.Stream, count) for i := 0; i < count; i++ { internal_cache.Get().MarkDownload(rv.Thumbnail.Sha256Hash) diff --git a/controllers/upload_controller/upload_controller.go b/controllers/upload_controller/upload_controller.go index 7936faa7dc038bf31ad44dbedb6f4d5b2af61ad0..b4fb52dc90865cc9b75db6763642a2e6a0254a33 100644 --- a/controllers/upload_controller/upload_controller.go +++ b/controllers/upload_controller/upload_controller.go @@ -1,13 +1,15 @@ package upload_controller import ( - "fmt" - "github.com/getsentry/sentry-go" "io" "io/ioutil" "strconv" "time" + "github.com/getsentry/sentry-go" + "github.com/turt2live/matrix-media-repo/util/ids" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/patrickmn/go-cache" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -19,7 +21,6 @@ import ( "github.com/turt2live/matrix-media-repo/storage/datastore" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" "github.com/turt2live/matrix-media-repo/util/util_byte_seeker" ) @@ -93,7 +94,7 @@ func EstimateContentLength(contentLength int64, contentLengthHeader string) int6 } func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string, filename string, userId string, origin string, ctx rcontext.RequestContext) (*types.Media, error) { - defer cleanup.DumpAndCloseStream(contents) + defer stream_util.DumpAndCloseStream(contents) var data io.ReadCloser if ctx.Config.Uploads.MaxSizeBytes > 0 { @@ -118,11 +119,7 @@ func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string return nil, errors.New("failed to generate a media ID after 10 rounds") } - mediaId, err = util.GenerateRandomString(64) - if err != nil { - return nil, err - } - mediaId, err = util.GetSha1OfString(mediaId + strconv.FormatInt(util.NowMillis(), 10)) + mediaId, err = ids.NewUniqueId() if err != nil { return nil, err } @@ -142,25 +139,7 @@ func UploadMedia(contents io.ReadCloser, contentLength int64, contentType string _ = recentMediaIds.Add(mediaId, true, cache.DefaultExpiration) - var existingFile *AlreadyUploadedFile = nil - ds, err := datastore.PickDatastore(common.KindLocalMedia, ctx) - if err != nil { - return nil, err - } - if ds.Type == "ipfs" { - // Do the upload now so we can pick the media ID to point to IPFS - info, err := ds.UploadFile(util_byte_seeker.NewByteSeeker(dataBytes), contentLength, ctx) - if err != nil { - return nil, err - } - existingFile = &AlreadyUploadedFile{ - DS: ds, - ObjectInfo: info, - } - mediaId = fmt.Sprintf("ipfs:%s", info.Location[len("ipfs/"):]) - } - - m, err := StoreDirect(existingFile, util_byte_seeker.NewByteSeeker(dataBytes), contentLength, contentType, filename, userId, origin, mediaId, common.KindLocalMedia, ctx, true) + m, err := StoreDirect(nil, util_byte_seeker.NewByteSeeker(dataBytes), contentLength, contentType, filename, userId, origin, mediaId, common.KindLocalMedia, ctx, true) if err != nil { return m, err } @@ -210,7 +189,7 @@ func StoreDirect(f *AlreadyUploadedFile, contents io.ReadCloser, expectedSize in return nil, err } - fInfo, err := ds.UploadFile(util.BytesToStream(contentBytes), expectedSize, ctx) + fInfo, err := ds.UploadFile(stream_util.BytesToStream(contentBytes), expectedSize, ctx) if err != nil { return nil, err } diff --git a/database/db.go b/database/db.go new file mode 100644 index 0000000000000000000000000000000000000000..7b1e17956aaf82d9c25673a34f888d79723ad5c8 --- /dev/null +++ b/database/db.go @@ -0,0 +1,61 @@ +package database + +import ( + "database/sql" + "errors" + "sync" + + "github.com/DavidHuie/gomigrate" + "github.com/sirupsen/logrus" + "github.com/turt2live/matrix-media-repo/common/config" +) + +type Database struct { + conn *sql.DB + Datastores *dsTableStatements +} + +var instance *Database +var singleton = &sync.Once{} + +func GetInstance() *Database { + if instance == nil { + singleton.Do(func() { + if err := openDatabase( + config.Get().Database.Postgres, + config.Get().Database.Pool.MaxConnections, + config.Get().Database.Pool.MaxIdle, + ); err != nil { + logrus.Fatal("Failed to set up database: ", err) + } + }) + } + return instance +} + +func openDatabase(connectionString string, maxConns int, maxIdleConns int) error { + d := &Database{} + var err error + + if d.conn, err = sql.Open("postgres", connectionString); err != nil { + return errors.New("error connecting to db: " + err.Error()) + } + d.conn.SetMaxOpenConns(maxConns) + d.conn.SetMaxIdleConns(maxIdleConns) + + // Run migrations + var migrator *gomigrate.Migrator + if migrator, err = gomigrate.NewMigratorWithLogger(d.conn, gomigrate.Postgres{}, config.Runtime.MigrationsPath, logrus.StandardLogger()); err != nil { + return errors.New("error setting up migrator: " + err.Error()) + } + if err = migrator.Migrate(); err != nil { + return errors.New("error running migrations: " + err.Error()) + } + + // Prepare the table accessors + if d.Datastores, err = prepareDatastoreTables(d.conn); err != nil { + return errors.New("failed to create datastores table accessor") + } + + return nil +} diff --git a/database/table_datastores.go b/database/table_datastores.go new file mode 100644 index 0000000000000000000000000000000000000000..fd2e72ce621c666de49828783607aa2100a68f2a --- /dev/null +++ b/database/table_datastores.go @@ -0,0 +1,132 @@ +package database + +import ( + "database/sql" + "errors" + "sync" + + "github.com/turt2live/matrix-media-repo/common/rcontext" +) + +type DbDatastore struct { + DatastoreId string + Type string + Uri string +} + +const selectAllDatastores = "SELECT datastore_id, ds_type, uri FROM datastores;" +const selectDatastore = "SELECT datastore_id, ds_type, uri FROM datastores WHERE datastore_id = $1;" +const selectDatastoreByUri = "SELECT datastore_id, ds_type, uri FROM datastores WHERE uri = $1;" +const insertDatastore = "INSERT INTO datastores (datastore_id, ds_type, uri) VALUES ($1, $2, $3);" + +var dsCacheByPath = sync.Map{} // [string] => Datastore +var dsCacheById = sync.Map{} // [string] => Datastore + +type dsTableStatements struct { + selectAllDatastores *sql.Stmt + selectDatastore *sql.Stmt + selectDatastoreByUri *sql.Stmt + insertDatastore *sql.Stmt +} + +type dsTableWithContext struct { + statements *dsTableStatements + ctx rcontext.RequestContext +} + +func prepareDatastoreTables(db *sql.DB) (*dsTableStatements, error) { + var err error + var stmts = &dsTableStatements{} + + if stmts.selectAllDatastores, err = db.Prepare(selectAllDatastores); err != nil { + return nil, errors.New("error preparing selectAllDatastores: " + err.Error()) + } + if stmts.selectDatastore, err = db.Prepare(selectDatastore); err != nil { + return nil, errors.New("error preparing selectDatastore: " + err.Error()) + } + if stmts.selectDatastoreByUri, err = db.Prepare(selectDatastoreByUri); err != nil { + return nil, errors.New("error preparing selectDatastoreByUri: " + err.Error()) + } + if stmts.insertDatastore, err = db.Prepare(insertDatastore); err != nil { + return nil, errors.New("error preparing insertDatastore: " + err.Error()) + } + + return stmts, nil +} + +func (s *dsTableStatements) Prepare(ctx rcontext.RequestContext) *dsTableWithContext { + return &dsTableWithContext{ + statements: s, + ctx: ctx, + } +} + +func (s *dsTableWithContext) GetDatastore(id string) (*DbDatastore, error) { + if v, ok := dsCacheById.Load(id); ok { + ds := v.(*DbDatastore) + return &DbDatastore{ + DatastoreId: ds.DatastoreId, + Type: ds.Type, + Uri: ds.Uri, + }, nil + } + + d := &DbDatastore{} + if err := s.statements.selectDatastore.QueryRowContext(s.ctx, id).Scan(&d.DatastoreId, &d.Type, &d.Uri); err != nil { + return nil, err + } + + dsCacheById.Store(d.DatastoreId, d) + dsCacheByPath.Store(d.Uri, d) + + return d, nil +} + +func (s *dsTableWithContext) GetDatastoreByUri(uri string) (*DbDatastore, error) { + if v, ok := dsCacheByPath.Load(uri); ok { + ds := v.(*DbDatastore) + return &DbDatastore{ + DatastoreId: ds.DatastoreId, + Type: ds.Type, + Uri: ds.Uri, + }, nil + } + + d := &DbDatastore{} + if err := s.statements.selectDatastoreByUri.QueryRowContext(s.ctx, uri).Scan(&d.DatastoreId, &d.Type, &d.Uri); err != nil { + return nil, err + } + + dsCacheById.Store(d.DatastoreId, d) + dsCacheByPath.Store(d.Uri, d) + + return d, nil +} + +func (s *dsTableWithContext) GetAllDatastores() ([]*DbDatastore, error) { + rows, err := s.statements.selectAllDatastores.QueryContext(s.ctx) + if err != nil { + return nil, err + } + + var results []*DbDatastore + for rows.Next() { + obj := &DbDatastore{} + if err = rows.Scan(&obj.DatastoreId, &obj.Type, &obj.Uri); err != nil { + return nil, err + } + } + + return results, nil +} + +func (s *dsTableWithContext) InsertDatastore(ds *DbDatastore) error { + if _, err := s.statements.insertDatastore.ExecContext(s.ctx, ds.DatastoreId, ds.Type, ds.Uri); err != nil { + return errors.New("error persiting datastore record: " + err.Error()) + } + + dsCacheById.Store(ds.DatastoreId, ds) + dsCacheByPath.Store(ds.Uri, ds) + + return nil +} diff --git a/docs/admin.md b/docs/admin.md index b35b4092e1bfc8eca8affa26a3adfa5e414d311e..2823b08ec35689d10743c004c21ab8367b205ae9 100644 --- a/docs/admin.md +++ b/docs/admin.md @@ -46,7 +46,9 @@ This will delete all media that has previously been quarantined, local or remote #### Purge individual record -URL: `POST /_matrix/media/unstable/admin/purge/<server>/<media id>?access_token=your_access_token` +URL: `POST /_matrix/media/unstable/admin/purge/media/<server>/<media id>?access_token=your_access_token` + +**Note**: Prior to v1.3, this endpoint did not require the `/media` component, but does now. This will delete the media record, regardless of it being local or remote. Can be called by homeserver administrators and the uploader to delete it. @@ -88,7 +90,9 @@ This API is unique in that it can allow administrators of configured homeservers #### Quarantine a specific record -URL: `POST /_matrix/media/unstable/admin/quarantine/<server>/<media id>?access_token=your_access_token` +URL: `POST /_matrix/media/unstable/admin/quarantine/media/<server>/<media id>?access_token=your_access_token` + +**Note**: Prior to v1.3, this endpoint did not require the `/media` component, but does now. The `<server>` and `<media id>` can be retrieved from an MXC URI (`mxc://<server>/<media id>`). @@ -358,7 +362,9 @@ The response is a list of all unfinished tasks: #### Getting information on a specific task -URL: `GET /_matrix/media/unstable/admin/tasks/<task ID>` +URL: `GET /_matrix/media/unstable/admin/task/<task ID>` + +**Note**: Prior to v1.3, this endpoint was "tasks" (plural). It is now singular. The response is the status of the task: ```json diff --git a/docs/ipfs.md b/docs/ipfs.md deleted file mode 100644 index 1b70006dde18717b4e333f2907807cbe2e9cd71d..0000000000000000000000000000000000000000 --- a/docs/ipfs.md +++ /dev/null @@ -1,12 +0,0 @@ -# IPFS Support - -TODO: An actual instructional document. - -## Bugs/TODO - -* [ ] Copies nearly everything into memory instead of streaming -* [ ] Downloads don't work because the nodes can be split sometimes (multiple links, RawData off the parent doesn't work) -* [ ] Delete support (see TODO) -* [ ] Overwrite support (if possible, might need to add support for changing media locations) -* [ ] General stability testing -* [ ] Use file names from database, not IPFS (because IPFS doesn't have any) \ No newline at end of file diff --git a/go.mod b/go.mod index 192c3b5de459214de23a86cefc532c340789dfb8..740d1fa501bc96e5cf3285a782f009c9216dd2ca 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,8 @@ require ( github.com/alioygur/is v1.0.3 github.com/bep/debounce v1.2.1 github.com/buckket/go-blurhash v1.1.0 + github.com/bwmarrin/snowflake v0.3.0 + github.com/cenk/backoff v2.2.1+incompatible // indirect github.com/cupcake/sigil v0.0.0-20131127230922-6bf9722f2ae8 github.com/dhowden/tag v0.0.0-20220618230019-adf36e896086 github.com/didip/tollbooth v4.0.2+incompatible @@ -25,14 +27,8 @@ require ( github.com/getsentry/sentry-go v0.13.0 github.com/go-redis/redis/v9 v9.0.0-beta.2 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/gorilla/mux v1.8.0 github.com/hashicorp/go-hclog v1.2.2 github.com/hashicorp/go-plugin v1.4.4 - github.com/ipfs/go-cid v0.2.0 - github.com/ipfs/go-ipfs-api v0.3.0 - github.com/ipfs/go-ipfs-files v0.1.1 - github.com/ipfs/interface-go-ipfs-core v0.7.0 - github.com/ipfs/kubo v0.14.0 github.com/k3a/html2text v1.0.8 github.com/kettek/apng v0.0.0-20220622131934-4e92eded13be github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f @@ -53,239 +49,56 @@ require ( golang.org/x/net v0.0.0-20220812174116-3211cb980234 ) +require github.com/julienschmidt/httprouter v1.3.0 + require ( - bazil.org/fuse v0.0.0-20200524192727-fb710f7dfd05 // indirect - github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/Jeffail/gabs v1.4.0 // indirect - github.com/Stebalien/go-bitfield v1.0.0 // indirect - github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect - github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/benbjohnson/clock v1.3.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/btcsuite/btcd v0.22.1 // indirect - github.com/btcsuite/btcd/btcec/v2 v2.2.1 // indirect - github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect - github.com/cenkalti/backoff v2.2.1+incompatible // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect - github.com/ceramicnetwork/go-dag-jose v0.1.0 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cheekybits/genny v1.0.0 // indirect - github.com/containerd/cgroups v1.0.4 // indirect - github.com/coreos/go-systemd/v22 v22.3.2 // indirect - github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect - github.com/cskr/pubsub v1.0.2 // indirect - github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect - github.com/dgraph-io/badger v1.6.2 // indirect - github.com/dgraph-io/ristretto v0.1.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/docker/go-units v0.4.0 // indirect github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e // indirect - github.com/elastic/gosigar v0.14.2 // indirect - github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect github.com/fatih/color v1.13.0 // indirect - github.com/flynn/noise v1.0.0 // indirect - github.com/francoispqt/gojay v1.2.13 // indirect github.com/go-errors/errors v1.4.2 // indirect - github.com/go-logr/logr v1.2.3 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect - github.com/golang/glog v1.0.0 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/gopacket v1.1.19 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2 // indirect + github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect github.com/hajimehoshi/go-mp3 v0.3.3 // indirect - github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/huin/goupnp v1.0.3 // indirect github.com/icza/bitio v1.1.0 // indirect - github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/go-bitfield v1.0.0 // indirect - github.com/ipfs/go-bitswap v0.9.0 // indirect - github.com/ipfs/go-block-format v0.0.3 // indirect - github.com/ipfs/go-blockservice v0.4.0 // indirect - github.com/ipfs/go-cidutil v0.1.0 // indirect - github.com/ipfs/go-datastore v0.5.1 // indirect - github.com/ipfs/go-delegated-routing v0.3.0 // indirect - github.com/ipfs/go-ds-badger v0.3.0 // indirect - github.com/ipfs/go-ds-flatfs v0.5.1 // indirect - github.com/ipfs/go-ds-leveldb v0.5.0 // indirect - github.com/ipfs/go-ds-measure v0.2.0 // indirect - github.com/ipfs/go-fetcher v1.6.1 // indirect - github.com/ipfs/go-filestore v1.2.0 // indirect - github.com/ipfs/go-fs-lock v0.0.7 // indirect - github.com/ipfs/go-graphsync v0.13.2 // indirect - github.com/ipfs/go-ipfs-blockstore v1.2.0 // indirect - github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect - github.com/ipfs/go-ipfs-delay v0.0.1 // indirect - github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect - github.com/ipfs/go-ipfs-exchange-interface v0.2.0 // indirect - github.com/ipfs/go-ipfs-exchange-offline v0.3.0 // indirect - github.com/ipfs/go-ipfs-keystore v0.0.2 // indirect - github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect - github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect - github.com/ipfs/go-ipfs-pq v0.0.2 // indirect - github.com/ipfs/go-ipfs-provider v0.7.1 // indirect - github.com/ipfs/go-ipfs-routing v0.2.1 // indirect - github.com/ipfs/go-ipfs-util v0.0.2 // indirect - github.com/ipfs/go-ipld-cbor v0.0.6 // indirect - github.com/ipfs/go-ipld-format v0.4.0 // indirect - github.com/ipfs/go-ipld-git v0.1.1 // indirect - github.com/ipfs/go-ipld-legacy v0.1.1 // indirect - github.com/ipfs/go-ipns v0.1.2 // indirect - github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipfs/go-log/v2 v2.5.1 // indirect - github.com/ipfs/go-merkledag v0.6.0 // indirect - github.com/ipfs/go-metrics-interface v0.0.1 // indirect - github.com/ipfs/go-mfs v0.2.1 // indirect - github.com/ipfs/go-namesys v0.5.0 // indirect - github.com/ipfs/go-path v0.3.0 // indirect - github.com/ipfs/go-peertaskqueue v0.7.1 // indirect - github.com/ipfs/go-unixfs v0.4.0 // indirect - github.com/ipfs/go-unixfsnode v1.4.0 // indirect - github.com/ipfs/go-verifcid v0.0.2 // indirect - github.com/ipld/edelweiss v0.1.5 // indirect - github.com/ipld/go-codec-dagpb v1.4.2 // indirect - github.com/ipld/go-ipld-prime v0.18.0 // indirect - github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/jbenet/goprocess v0.1.4 // indirect github.com/jfreymuth/oggvorbis v1.0.3 // indirect github.com/jfreymuth/vorbis v1.0.2 // indirect + github.com/jonboulle/clockwork v0.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.15.9 // indirect github.com/klauspost/cpuid/v2 v2.1.0 // indirect - github.com/koron/go-ssdp v0.0.3 // indirect - github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-cidranger v1.1.0 // indirect - github.com/libp2p/go-doh-resolver v0.4.0 // indirect - github.com/libp2p/go-eventbus v0.2.1 // indirect - github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p v0.20.3 // indirect - github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect - github.com/libp2p/go-libp2p-core v0.16.1 // indirect - github.com/libp2p/go-libp2p-discovery v0.7.0 // indirect - github.com/libp2p/go-libp2p-kad-dht v0.16.0 // indirect - github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect - github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect - github.com/libp2p/go-libp2p-peerstore v0.7.1 // indirect - github.com/libp2p/go-libp2p-pubsub v0.7.1 // indirect - github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect - github.com/libp2p/go-libp2p-record v0.1.3 // indirect - github.com/libp2p/go-libp2p-resource-manager v0.3.0 // indirect - github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect - github.com/libp2p/go-libp2p-swarm v0.11.0 // indirect - github.com/libp2p/go-libp2p-xor v0.1.0 // indirect - github.com/libp2p/go-mplex v0.7.0 // indirect - github.com/libp2p/go-msgio v0.2.0 // indirect - github.com/libp2p/go-nat v0.1.0 // indirect - github.com/libp2p/go-netroute v0.2.0 // indirect - github.com/libp2p/go-openssl v0.0.7 // indirect - github.com/libp2p/go-reuseport v0.2.0 // indirect - github.com/libp2p/go-yamux/v3 v3.1.2 // indirect - github.com/libp2p/zeroconf/v2 v2.1.1 // indirect - github.com/lucas-clemente/quic-go v0.27.1 // indirect - github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect - github.com/marten-seemann/qtls-go1-17 v0.1.2 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.2 // indirect - github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect + github.com/kr/pretty v0.3.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mewkiz/flac v1.0.7 // indirect github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77 // indirect - github.com/miekg/dns v1.1.50 // indirect - github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect - github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.0.4 // indirect - github.com/multiformats/go-base36 v0.1.0 // indirect - github.com/multiformats/go-multiaddr v0.6.0 // indirect - github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multibase v0.1.1 // indirect - github.com/multiformats/go-multicodec v0.5.0 // indirect - github.com/multiformats/go-multihash v0.2.1 // indirect - github.com/multiformats/go-multistream v0.3.3 // indirect - github.com/multiformats/go-varint v0.0.6 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo v1.16.5 // indirect - github.com/opencontainers/runtime-spec v1.0.2 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/openzipkin/zipkin-go v0.4.0 // indirect - github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/raulk/go-watchdog v1.3.0 // indirect - github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect - github.com/tidwall/gjson v1.14.3 // indirect - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect - github.com/wI2L/jsondiff v0.2.0 // indirect - github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect - github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c // indirect - github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect - github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect - github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect - github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b // indirect - github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect - go.opencensus.io v0.23.0 // indirect - go.opentelemetry.io/otel v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/jaeger v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/zipkin v1.9.0 // indirect - go.opentelemetry.io/otel/sdk v1.9.0 // indirect - go.opentelemetry.io/otel/trace v1.9.0 // indirect - go.opentelemetry.io/proto/otlp v0.19.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/dig v1.15.0 // indirect - go.uber.org/fx v1.18.1 // indirect - go.uber.org/multierr v1.8.0 // indirect - go.uber.org/zap v1.22.0 // indirect - go4.org v0.0.0-20201209231011-d4a079459e60 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect + github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd // indirect + github.com/smartystreets/assertions v1.0.0 // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.1.12 // indirect - golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect google.golang.org/protobuf v1.28.1 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - lukechampine.com/blake3 v1.1.7 // indirect ) require ( github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect - github.com/cenk/backoff v2.2.1+incompatible // indirect github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect github.com/go-sql-driver/mysql v1.5.0 // indirect - github.com/golang/snappy v0.0.4 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect diff --git a/go.sum b/go.sum index a70ad5d10f253a39b9857c23c2e1e93ab01e3bb3..a052c1bccf4e69fcb3d47c22504bfd64420fb028 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,5 @@ -bazil.org/fuse v0.0.0-20200524192727-fb710f7dfd05 h1:UrYe9YkT4Wpm6D+zByEyCJQzDqTPXqTDUI7bZ41i9VE= -bazil.org/fuse v0.0.0-20200524192727-fb710f7dfd05/go.mod h1:h0h5FBYpXThbvSfTqthw+0I4nmHnhTHkO5BoOHsBWqg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.31.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.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= 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= @@ -34,17 +30,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo 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= -dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= -dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= -dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= -git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= -github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -54,24 +40,10 @@ github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Jeffail/tunny v0.1.4 h1:chtpdz+nUtaYQeCKlNBg6GycFF/kGVHOr6A3cmzTJXs= github.com/Jeffail/tunny v0.1.4/go.mod h1:P8xAx4XQl0xsuhjX1DtfaMDCSuavzdb2rwbd0lk+fvo= -github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/sarama v1.30.0/go.mod h1:zujlQQx1kzHsh4jfV1USnptCQrHAEZ2Hk8fTKCulPVs= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/Shopify/toxiproxy/v2 v2.1.6-0.20210914104332-15ea381dcdae/go.mod h1:/cvHQkZ1fst0EmZnA5dFtiQdWCNCFYzb+uE2vqVgvx0= -github.com/Stebalien/go-bitfield v0.0.1/go.mod h1:GNjFpasyUVkHMsfEOk8EFLJ9syQ6SI+XWrX9Wf2XH0s= -github.com/Stebalien/go-bitfield v1.0.0 h1:z8eb6tyNR24GRWav81CEtcsVU1JeP+gaYBomOSKz5gQ= -github.com/Stebalien/go-bitfield v1.0.0/go.mod h1:+uJt8nBkrY+u2tapleM6VtVRcnM8LCvAED/0tWo+jVk= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/adrium/goheif v0.0.0-20210309200126-b184a7b446fa h1:ISwtQHwIaKiwhFFmBOIib1o1jH3UvtKPnsEo45zsVj0= github.com/adrium/goheif v0.0.0-20210309200126-b184a7b446fa/go.mod h1:aKVJoQ0cc9K5Xb058XSnnAxXLliR97qbSqWBlm5ca1E= -github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= @@ -81,159 +53,44 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= -github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= -github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5 h1:iW0a5ljuFxkLGPNem5Ui+KBjFJzKg4Fv2fnxe4dvzpM= -github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5/go.mod h1:Y2QMoi1vgtOIfc+6DhrMOGkLoGzqSV2rKp4Sm+opsyA= github.com/alioygur/is v1.0.3 h1:DiBxR66HkJNC2EQVHHZekns5wphlvbwCAaYpk3wPDLc= github.com/alioygur/is v1.0.3/go.mod h1:fmXi78K26iMaOs0fINRVLl1TIPCYcLfOopoZ5+mc8AE= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/benbjohnson/clock v1.0.2/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.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= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8= -github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= -github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= -github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94= -github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= -github.com/btcsuite/btcd v0.22.1 h1:CnwP9LM/M9xuRrGSCGeMVs9iv09uMqwsVX7EeIpgV2c= -github.com/btcsuite/btcd v0.22.1/go.mod h1:wqgTSL29+50LRkmOVknEdmt8ZojIzhuWvgu/iptuN7Y= -github.com/btcsuite/btcd/btcec/v2 v2.2.1 h1:xP60mv8fvp+0khmrN0zTdPC3cNm24rfeE6lh2R/Yv3E= -github.com/btcsuite/btcd/btcec/v2 v2.2.1/go.mod h1:9/CSmJxmuvqzX9Wh2fXMWToLOHhPd11lSPuIupwTkI8= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= -github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1/go.mod h1:7SFka0XMvUgj3hfZtydOrQY2mwhPclbT2snogU7SQQc= -github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= -github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= -github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= -github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= -github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= -github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= -github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= -github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= -github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do= github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8= -github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= +github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/cenk/backoff v2.2.1+incompatible h1:djdFT7f4gF2ttuzRKPbMOWgZajgesItGLwG5FTQKmmE= github.com/cenk/backoff v2.2.1+incompatible/go.mod h1:7FtoeaSnHoZnmZzz47cM35Y9nSW7tNyaidugnHTaFDE= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/ceramicnetwork/go-dag-jose v0.1.0 h1:yJ/HVlfKpnD3LdYP03AHyTvbm3BpPiz2oZiOeReJRdU= -github.com/ceramicnetwork/go-dag-jose v0.1.0/go.mod h1:qYA1nYt0X8u4XoMAVoOV3upUVKtrxy/I670Dg5F0wjI= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= 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/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= -github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= -github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= -github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= -github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 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/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/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= -github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= -github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= -github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.2.1-0.20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/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/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= -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/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/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 h1:HVTnpeuvF6Owjd5mniCL8DEXo7uYXdQEmOP4FJbV5tg= -github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3/go.mod h1:p1d6YEZWvFzEh4KLyvBcVSnrfNDDvK2zfK/4x2v/4pE= -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/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= -github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= github.com/cupcake/sigil v0.0.0-20131127230922-6bf9722f2ae8 h1:OPuOoDEMJx86BQOPt4rfZvOjquI3Ym3XUE1Dy+gQoVs= github.com/cupcake/sigil v0.0.0-20131127230922-6bf9722f2ae8/go.mod h1:paJ9TzhB9Ke4jQk99LQSyBdSILWICp01d7R0S8CSCPI= github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= -github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/davidlazar/go-crypto v0.0.0-20170701192655-dcfb0a7ac018/go.mod h1:rQYf4tfk5sSwFsnDg3qYaBxSjsD9S8+59vW0dKUgme4= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= -github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= -github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= -github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= -github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ= -github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= -github.com/dgraph-io/badger v1.6.1/go.mod h1:FRmFw3uxvcpa8zG3Rxs0th+hCLIuaQg8HlNV5bjgnuU= -github.com/dgraph-io/badger v1.6.2 h1:mNw0qs90GVgGGWylh0umH5iag1j6n/PeJtNvL6KY/x8= -github.com/dgraph-io/badger v1.6.2/go.mod h1:JW2yswe3V058sS0kZ2h/AXeDSqFjxnZcRrVH//y2UQE= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= -github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dhowden/tag v0.0.0-20220618230019-adf36e896086 h1:ORubSQoKnncsBnR4zD9CuYFJCPOCuSNEpWEZrDdBXkc= @@ -244,8 +101,6 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1 github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/djherbis/stream v1.4.0 h1:aVD46WZUiq5kJk55yxJAyw6Kuera6kmC3i2vEQyW/AE= github.com/djherbis/stream v1.4.0/go.mod h1:cqjC1ZRq3FFwkGmUtHwcldbnW8f0Q4YuVsGW1eAFtOk= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E= github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8= github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b h1:NgNuLvW/gAFKU30ULWW0gtkCt56JfB7FrZ2zyo0wT8I= @@ -257,62 +112,28 @@ github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd/go.mod h1:7I+3P github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8= github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e h1:IxIbA7VbCNrwumIYjDoMOdf4KOSkMC6NJE4s8oRbE7E= github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 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/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/dyatlov/go-oembed v0.0.0-20191103150536-a57c85b3b37c h1:MEV1LrQtCBGacXajlT4CSuYWbZuLl/qaZVqwoOmwAbU= github.com/dyatlov/go-oembed v0.0.0-20191103150536-a57c85b3b37c/go.mod h1:DjlDZiZGRRKbiJZmiEiiXozsBQAQzHmxwHKFeXifL2g= github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a h1:etIrTD8BQqzColk9nKRusM9um5+1q0iOEJLqfBMIK64= github.com/dyatlov/go-opengraph/opengraph v0.0.0-20220524092352-606d7b1e5f8a/go.mod h1:emQhSYTXqB0xxjLITTw4EaWZ+8IIQYw+kx9GqNUKdLg= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= -github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= -github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 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.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.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A= -github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c= github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU= github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= -github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= -github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= -github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og= -github.com/frankban/quicktest v1.14.2/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q= @@ -322,11 +143,9 @@ github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebK github.com/getsentry/sentry-go v0.13.0 h1:20dgTiUSfxRB/EhMPtxcL9ZEbM1ZdR+W/7f7NWD+xWo= github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs= github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498= github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE= -github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs= @@ -337,39 +156,18 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-redis/redis/v9 v9.0.0-beta.2 h1:ZSr84TsnQyKMAg8gnV+oawuQezeJR11/09THcWCQzr4= github.com/go-redis/redis/v9 v9.0.0-beta.2/go.mod h1:Bldcd/M/bm9HbnNPi/LUtYBSD8ttcZYBMupwMXhdU0o= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.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 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -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 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= @@ -377,15 +175,9 @@ github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgR github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 h1:gtexQ/VGyN+VVFRXSFiguSNcXmS6rkKT+X7FdIrTtfo= github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -393,10 +185,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= 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.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= @@ -413,9 +202,6 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -425,20 +211,11 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -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/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -449,353 +226,34 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -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/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/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2 h1:BqHID5W5qnMkug0Z8UmL8tN0gAy4jQ+B4WFt8cCgluU= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.2/go.mod h1:ZbS3MZTZq/apAfAEHGoB5HbsQQstoqP92SjAqtQ9zeg= -github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= -github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/hajimehoshi/go-mp3 v0.3.3 h1:cWnfRdpye2m9ElSoVqneYRcpt/l3ijttgjMeQh+r+FE= github.com/hajimehoshi/go-mp3 v0.3.3/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos= -github.com/hannahhoward/cbor-gen-for v0.0.0-20200817222906-ea96cece81f1/go.mod h1:jvfsLIxk0fY/2BKSQ1xf2406AKA5dwMmKKv0ADcOfN8= -github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e h1:3YKHER4nmd7b5qy5t0GWDTwSn4OyRgfAXSmo6VnryBY= -github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e/go.mod h1:I8h3MITA53gN9OnWGCgaMa0JWVRdXthWw4M3CPM54OY= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v1.2.2 h1:ihRI7YFwcZdiSD7SIenIhHfQH3OuDvWerAUBZbeQS3M= github.com/hashicorp/go-hclog v1.2.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -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.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -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-plugin v1.4.4 h1:NVdrSdFRt3SkZtNckJ6tog7gbpRrcbOjQi/rgF7JYWQ= github.com/hashicorp/go-plugin v1.4.4/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= -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-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.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= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goupnp v1.0.2/go.mod h1:0dxJBVBHqTMjIUMkESDTNgOOx/Mw5wYIfyFmdzSamkM= -github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= -github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A= github.com/icza/bitio v1.1.0 h1:ysX4vtldjdi3Ygai5m1cWy4oLkhWTAi+SyO6HC8L9T0= github.com/icza/bitio v1.1.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A= github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k= github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/ipfs/bbloom v0.0.1/go.mod h1:oqo8CVWsJFMOZqTglBG4wydCE4IQA/G2/SEofB0rjUI= -github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= -github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= -github.com/ipfs/go-bitfield v1.0.0 h1:y/XHm2GEmD9wKngheWNNCNL0pzrWXZwCdQGv1ikXknQ= -github.com/ipfs/go-bitfield v1.0.0/go.mod h1:N/UiujQy+K+ceU1EF5EkVd1TNqevLrCQMIcAEPrdtus= -github.com/ipfs/go-bitswap v0.0.9/go.mod h1:kAPf5qgn2W2DrgAcscZ3HrM9qh4pH+X8Fkk3UPrwvis= -github.com/ipfs/go-bitswap v0.1.0/go.mod h1:FFJEf18E9izuCqUtHxbWEvq+reg7o4CW5wSAE1wsxj0= -github.com/ipfs/go-bitswap v0.1.2/go.mod h1:qxSWS4NXGs7jQ6zQvoPY3+NmOfHHG47mhkiLzBpJQIs= -github.com/ipfs/go-bitswap v0.1.8/go.mod h1:TOWoxllhccevbWFUR2N7B1MTSVVge1s6XSMiCSA4MzM= -github.com/ipfs/go-bitswap v0.3.4/go.mod h1:4T7fvNv/LmOys+21tnLzGKncMeeXUYUd1nUiJ2teMvI= -github.com/ipfs/go-bitswap v0.5.1/go.mod h1:P+ckC87ri1xFLvk74NlXdP0Kj9RmWAh4+H78sC6Qopo= -github.com/ipfs/go-bitswap v0.6.0/go.mod h1:Hj3ZXdOC5wBJvENtdqsixmzzRukqd8EHLxZLZc3mzRA= -github.com/ipfs/go-bitswap v0.9.0 h1:/dZi/XhUN/aIk78pI4kaZrilUglJ+7/SCmOHWIpiy8E= -github.com/ipfs/go-bitswap v0.9.0/go.mod h1:zkfBcGWp4dQTQd0D0akpudhpOVUAJT9GbH9tDmR8/s4= -github.com/ipfs/go-block-format v0.0.1/go.mod h1:DK/YYcsSUIVAFNwo/KZCdIIbpN0ROH/baNLgayt4pFc= -github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= -github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= -github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= -github.com/ipfs/go-blockservice v0.0.7/go.mod h1:EOfb9k/Y878ZTRY/CH0x5+ATtaipfbRhbvNSdgc/7So= -github.com/ipfs/go-blockservice v0.1.0/go.mod h1:hzmMScl1kXHg3M2BjTymbVPjv627N7sYcvYaKbop39M= -github.com/ipfs/go-blockservice v0.1.4/go.mod h1:OTZhFpkgY48kNzbgyvcexW9cHrpjBYIjSR0KoDOFOLU= -github.com/ipfs/go-blockservice v0.2.1/go.mod h1:k6SiwmgyYgs4M/qt+ww6amPeUH9EISLRBnvUurKJhi8= -github.com/ipfs/go-blockservice v0.3.0/go.mod h1:P5ppi8IHDC7O+pA0AlGTF09jruB2h+oP3wVVaZl8sfk= -github.com/ipfs/go-blockservice v0.4.0 h1:7MUijAW5SqdsqEW/EhnNFRJXVF8mGU5aGhZ3CQaCWbY= -github.com/ipfs/go-blockservice v0.4.0/go.mod h1:kRjO3wlGW9mS1aKuiCeGhx9K1DagQ10ACpVO59qgAx4= -github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= -github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M= -github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= -github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= -github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o= -github.com/ipfs/go-cid v0.2.0 h1:01JTiihFq9en9Vz0lc0VDWvZe/uBonGpzo4THP0vcQ0= -github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro= -github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s= -github.com/ipfs/go-cidutil v0.1.0 h1:RW5hO7Vcf16dplUU60Hs0AKDkQAVPVplr7lk97CFL+Q= -github.com/ipfs/go-cidutil v0.1.0/go.mod h1:e7OEVBMIv9JaOxt9zaGEmAoSlXW9jdFZ5lP/0PwcfpA= -github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.0.5/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE= -github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= -github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw= -github.com/ipfs/go-datastore v0.4.0/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.4/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA= -github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w3fyfrmmJs= -github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-datastore v0.5.1 h1:WkRhLuISI+XPD0uk3OskB0fYFSyqK8Ob5ZYew9Qa1nQ= -github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= -github.com/ipfs/go-delegated-routing v0.3.0 h1:pF5apOJ/xdQkj22mRahW9GmSuCkgMLparKZWKJBO4CE= -github.com/ipfs/go-delegated-routing v0.3.0/go.mod h1:2w79E1/G9YOaxyJJQgqIFSQaa/GdS2zSATEpK8aJUBM= -github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= -github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= -github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8= -github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s= -github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk= -github.com/ipfs/go-ds-badger v0.2.1/go.mod h1:Tx7l3aTph3FMFrRS838dcSJh+jjA7cX9DrGVwx/NOwE= -github.com/ipfs/go-ds-badger v0.2.3/go.mod h1:pEYw0rgg3FIrywKKnL+Snr+w/LjJZVMTBRn4FS6UHUk= -github.com/ipfs/go-ds-badger v0.2.7/go.mod h1:02rnztVKA4aZwDuaRPTf8mpqcKmXP7mLl6JPxd14JHA= -github.com/ipfs/go-ds-badger v0.3.0 h1:xREL3V0EH9S219kFFueOYJJTcjgNSZ2HY1iSvN7U1Ro= -github.com/ipfs/go-ds-badger v0.3.0/go.mod h1:1ke6mXNqeV8K3y5Ak2bAA0osoTfmxUdupVCGm4QUIek= -github.com/ipfs/go-ds-flatfs v0.5.1 h1:ZCIO/kQOS/PSh3vcF1H6a8fkRGS7pOfwfPdx4n/KJH4= -github.com/ipfs/go-ds-flatfs v0.5.1/go.mod h1:RWTV7oZD/yZYBKdbVIFXTX2fdY2Tbvl94NsWqmoyAX4= -github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc= -github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8= -github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ds-leveldb v0.4.2/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s= -github.com/ipfs/go-ds-leveldb v0.5.0 h1:s++MEBbD3ZKc9/8/njrn4flZLnCuY9I79v94gBUNumo= -github.com/ipfs/go-ds-leveldb v0.5.0/go.mod h1:d3XG9RUDzQ6V4SHi8+Xgj9j1XuEk1z82lquxrVbml/Q= -github.com/ipfs/go-ds-measure v0.2.0 h1:sG4goQe0KDTccHMyT45CY1XyUbxe5VwTKpg2LjApYyQ= -github.com/ipfs/go-ds-measure v0.2.0/go.mod h1:SEUD/rE2PwRa4IQEC5FuNAmjJCyYObZr9UvVh8V3JxE= -github.com/ipfs/go-fetcher v1.5.0/go.mod h1:5pDZ0393oRF/fHiLmtFZtpMNBQfHOYNPtryWedVuSWE= -github.com/ipfs/go-fetcher v1.6.1 h1:UFuRVYX5AIllTiRhi5uK/iZkfhSpBCGX7L70nSZEmK8= -github.com/ipfs/go-fetcher v1.6.1/go.mod h1:27d/xMV8bodjVs9pugh/RCjjK2OZ68UgAMspMdingNo= -github.com/ipfs/go-filestore v1.2.0 h1:O2wg7wdibwxkEDcl7xkuQsPvJFRBVgVSsOJ/GP6z3yU= -github.com/ipfs/go-filestore v1.2.0/go.mod h1:HLJrCxRXquTeEEpde4lTLMaE/MYJZD7WHLkp9z6+FF8= -github.com/ipfs/go-fs-lock v0.0.7 h1:6BR3dajORFrFTkb5EpCUFIAypsoxpGpDSVUdFwzgL9U= -github.com/ipfs/go-fs-lock v0.0.7/go.mod h1:Js8ka+FNYmgQRLrRXzU3CB/+Csr1BwrRilEcvYrHhhc= -github.com/ipfs/go-graphsync v0.13.2 h1:+7IjTrdg3+3iwtPXSkLoxvhaByS3+3b9NStMAowFqkw= -github.com/ipfs/go-graphsync v0.13.2/go.mod h1:TO1Y65spARny/t37hkid5xCpQJ6vR7A7VFTEUb0Z6eA= -github.com/ipfs/go-ipfs-api v0.3.0 h1:ZzVrsTV31Z53ZlUare6a5UJ46lC7lW93q/s1/fXyATk= -github.com/ipfs/go-ipfs-api v0.3.0/go.mod h1:A1naQGm0Jg01GxDq7oDyVSZxt20SuRTNIBFNZJgPDmg= -github.com/ipfs/go-ipfs-blockstore v0.0.1/go.mod h1:d3WClOmRQKFnJ0Jz/jj/zmksX0ma1gROTlovZKBmN08= -github.com/ipfs/go-ipfs-blockstore v0.1.0/go.mod h1:5aD0AvHPi7mZc6Ci1WCAhiBQu2IsfTduLl+422H6Rqw= -github.com/ipfs/go-ipfs-blockstore v0.1.4/go.mod h1:Jxm3XMVjh6R17WvxFEiyKBLUGr86HgIYJW/D/MwqeYQ= -github.com/ipfs/go-ipfs-blockstore v0.2.1/go.mod h1:jGesd8EtCM3/zPgx+qr0/feTXGUeRai6adgwC+Q+JvE= -github.com/ipfs/go-ipfs-blockstore v1.1.2/go.mod h1:w51tNR9y5+QXB0wkNcHt4O2aSZjTdqaEWaQdSxEyUOY= -github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3j8qz0ykw= -github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= -github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= -github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= -github.com/ipfs/go-ipfs-chunker v0.0.1/go.mod h1:tWewYK0we3+rMbOh7pPFGDyypCtvGcBFymgY4rSDLAw= -github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= -github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= -github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= -github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= -github.com/ipfs/go-ipfs-ds-help v0.0.1/go.mod h1:gtP9xRaZXqIQRh1HRpp595KbBEdgqWFxefeVKOV8sxo= -github.com/ipfs/go-ipfs-ds-help v0.1.1/go.mod h1:SbBafGJuGsPI/QL3j9Fc5YPLeAu+SzOkI0gFwAg+mOs= -github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= -github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= -github.com/ipfs/go-ipfs-exchange-interface v0.0.1/go.mod h1:c8MwfHjtQjPoDyiy9cFquVtVHkO9b9Ob3FG91qJnWCM= -github.com/ipfs/go-ipfs-exchange-interface v0.1.0/go.mod h1:ych7WPlyHqFvCi/uQI48zLZuAWVP5iTQPXEfVaw5WEI= -github.com/ipfs/go-ipfs-exchange-interface v0.2.0 h1:8lMSJmKogZYNo2jjhUs0izT+dck05pqUw4mWNW9Pw6Y= -github.com/ipfs/go-ipfs-exchange-interface v0.2.0/go.mod h1:z6+RhJuDQbqKguVyslSOuVDhqF9JtTrO3eptSAiW2/Y= -github.com/ipfs/go-ipfs-exchange-offline v0.0.1/go.mod h1:WhHSFCVYX36H/anEKQboAzpUws3x7UeEGkzQc3iNkM0= -github.com/ipfs/go-ipfs-exchange-offline v0.1.1/go.mod h1:vTiBRIbzSwDD0OWm+i3xeT0mO7jG2cbJYatp3HPk5XY= -github.com/ipfs/go-ipfs-exchange-offline v0.2.0/go.mod h1:HjwBeW0dvZvfOMwDP0TSKXIHf2s+ksdP4E3MLDRtLKY= -github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA= -github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s= -github.com/ipfs/go-ipfs-files v0.0.3/go.mod h1:INEFm0LL2LWXBhNJ2PMIIb2w45hpXgPjNoE7yA8Y1d4= -github.com/ipfs/go-ipfs-files v0.0.8/go.mod h1:wiN/jSG8FKyk7N0WyctKSvq3ljIa2NNTiZB55kpTdOs= -github.com/ipfs/go-ipfs-files v0.0.9/go.mod h1:aFv2uQ/qxWpL/6lidWvnSQmaVqCrf0TBGoUr+C1Fo84= -github.com/ipfs/go-ipfs-files v0.1.1 h1:/MbEowmpLo9PJTEQk16m9rKzUHjeP4KRU9nWJyJO324= -github.com/ipfs/go-ipfs-files v0.1.1/go.mod h1:8xkIrMWH+Y5P7HvJ4Yc5XWwIW2e52dyXUiC0tZyjDbM= -github.com/ipfs/go-ipfs-keystore v0.0.2 h1:Fa9xg9IFD1VbiZtrNLzsD0GuELVHUFXCWF64kCPfEXU= -github.com/ipfs/go-ipfs-keystore v0.0.2/go.mod h1:H49tRmibOEs7gLMgbOsjC4dqh1u5e0R/SWuc2ScfgSo= -github.com/ipfs/go-ipfs-pinner v0.2.1 h1:kw9hiqh2p8TatILYZ3WAfQQABby7SQARdrdA+5Z5QfY= -github.com/ipfs/go-ipfs-pinner v0.2.1/go.mod h1:l1AtLL5bovb7opnG77sh4Y10waINz3Y1ni6CvTzx7oo= -github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs= -github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A= -github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= -github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= -github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= -github.com/ipfs/go-ipfs-provider v0.7.1 h1:eKToBUAb6ZY8iiA6AYVxzW4G1ep67XUaaEBUIYpxhfw= -github.com/ipfs/go-ipfs-provider v0.7.1/go.mod h1:QwdDYRYnC5sYGLlOwVDY/0ZB6T3zcMtu+5+GdGeUuw8= -github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs= -github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY= -github.com/ipfs/go-ipfs-routing v0.2.1 h1:E+whHWhJkdN9YeoHZNj5itzc+OR292AJ2uE9FFiW0BY= -github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM= -github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= -github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= -github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= -github.com/ipfs/go-ipld-cbor v0.0.2/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= -github.com/ipfs/go-ipld-cbor v0.0.3/go.mod h1:wTBtrQZA3SoFKMVkp6cn6HMRteIB1VsmHA0AQFOn7Nc= -github.com/ipfs/go-ipld-cbor v0.0.4/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= -github.com/ipfs/go-ipld-cbor v0.0.5/go.mod h1:BkCduEx3XBCO6t2Sfo5BaHzuok7hbhdMm9Oh8B2Ftq4= -github.com/ipfs/go-ipld-cbor v0.0.6 h1:pYuWHyvSpIsOOLw4Jy7NbBkCyzLDcl64Bf/LZW7eBQ0= -github.com/ipfs/go-ipld-cbor v0.0.6/go.mod h1:ssdxxaLJPXH7OjF5V4NSjBbcfh+evoR4ukuru0oPXMA= -github.com/ipfs/go-ipld-format v0.0.1/go.mod h1:kyJtbkDALmFHv3QR6et67i35QzO3S0dCDnkOJhcZkms= -github.com/ipfs/go-ipld-format v0.0.2/go.mod h1:4B6+FM2u9OJ9zCV+kSbgFAZlOrv1Hqbf0INGQgiKf9k= -github.com/ipfs/go-ipld-format v0.2.0/go.mod h1:3l3C1uKoadTPbeNfrDi+xMInYKlx2Cvg1BuydPSdzQs= -github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= -github.com/ipfs/go-ipld-format v0.4.0 h1:yqJSaJftjmjc9jEOFYlpkwOLVKv68OD27jFLlSghBlQ= -github.com/ipfs/go-ipld-format v0.4.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= -github.com/ipfs/go-ipld-git v0.1.1 h1:TWGnZjS0htmEmlMFEkA3ogrNCqWjIxwr16x1OsdhG+Y= -github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYDpKUkJubI= -github.com/ipfs/go-ipld-legacy v0.1.0/go.mod h1:86f5P/srAmh9GcIcWQR9lfFLZPrIyyXQeVlOWeeWEuI= -github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2cdcc= -github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg= -github.com/ipfs/go-ipns v0.1.2 h1:O/s/0ht+4Jl9+VoxoUo0zaHjnZUS+aBQIKTuzdZ/ucI= -github.com/ipfs/go-ipns v0.1.2/go.mod h1:ioQ0j02o6jdIVW+bmi18f4k2gRf0AV3kZ9KeHYHICnQ= -github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= -github.com/ipfs/go-log v1.0.2/go.mod h1:1MNjMxe0u6xvJZgeqbJ8vdo2TKaGwZ1a0Bpza+sr2Sk= -github.com/ipfs/go-log v1.0.3/go.mod h1:OsLySYkwIbiSUR/yBTdv1qPtcE4FW3WPWk/ewz9Ru+A= -github.com/ipfs/go-log v1.0.4/go.mod h1:oDCg2FkjogeFOhqqb+N39l2RpTNPL6F/StPkB3kPgcs= -github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= -github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= -github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0= -github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw= -github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM= -github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= -github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g= -github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= -github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto= -github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk= -github.com/ipfs/go-merkledag v0.3.2/go.mod h1:fvkZNNZixVW6cKSZ/JfLlON5OlgTXNdRLz0p6QG/I2M= -github.com/ipfs/go-merkledag v0.5.1/go.mod h1:cLMZXx8J08idkp5+id62iVftUQV+HlYJ3PIhDfZsjA4= -github.com/ipfs/go-merkledag v0.6.0 h1:oV5WT2321tS4YQVOPgIrWHvJ0lJobRTerU+i9nmUCuA= -github.com/ipfs/go-merkledag v0.6.0/go.mod h1:9HSEwRd5sV+lbykiYP+2NC/3o6MZbKNaa4hfNcH5iH0= -github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= -github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= -github.com/ipfs/go-mfs v0.2.1 h1:5jz8+ukAg/z6jTkollzxGzhkl3yxm022Za9f2nL5ab8= -github.com/ipfs/go-mfs v0.2.1/go.mod h1:Woj80iuw4ajDnIP6+seRaoHpPsc9hmL0pk/nDNDWP88= -github.com/ipfs/go-namesys v0.5.0 h1:vZEkdqxRiSnxBBJrvYTkwHYBFgibGUSpNtg9BHRyN+o= -github.com/ipfs/go-namesys v0.5.0/go.mod h1:zZOme8KDAUYDl4f5MnWSiTRhoxcM7kLkZIyps/HV/S0= -github.com/ipfs/go-path v0.0.7/go.mod h1:6KTKmeRnBXgqrTvzFrPV3CamxcgvXX/4z79tfAd2Sno= -github.com/ipfs/go-path v0.0.9/go.mod h1:VpDkSBKQ9EFQOUgi54Tq/O/tGi8n1RfYNks13M3DEs8= -github.com/ipfs/go-path v0.2.1/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= -github.com/ipfs/go-path v0.3.0 h1:tkjga3MtpXyM5v+3EbRvOHEoo+frwi4oumw5K+KYWyA= -github.com/ipfs/go-path v0.3.0/go.mod h1:NOScsVgxfC/eIw4nz6OiGwK42PjaSJ4Y/ZFPn1Xe07I= -github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP1MX6Kd+aN+rMQ= -github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= -github.com/ipfs/go-peertaskqueue v0.1.1/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U= -github.com/ipfs/go-peertaskqueue v0.2.0/go.mod h1:5/eNrBEbtSKWCG+kQK8K8fGNixoYUnr+P7jivavs9lY= -github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= -github.com/ipfs/go-peertaskqueue v0.7.1 h1:7PLjon3RZwRQMgOTvYccZ+mjzkmds/7YzSWKFlBAypE= -github.com/ipfs/go-peertaskqueue v0.7.1/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU= -github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw= -github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o= -github.com/ipfs/go-unixfs v0.4.0 h1:qSyyxfB/OiDdWHYiSbyaqKC7zfSE/TFL0QdwkRjBm20= -github.com/ipfs/go-unixfs v0.4.0/go.mod h1:I7Nqtm06HgOOd+setAoCU6rf/HgVFHE+peeNuOv/5+g= -github.com/ipfs/go-unixfsnode v1.1.2/go.mod h1:5dcE2x03pyjHk4JjamXmunTMzz+VUtqvPwZjIEkfV6s= -github.com/ipfs/go-unixfsnode v1.4.0 h1:9BUxHBXrbNi8mWHc6j+5C580WJqtVw9uoeEKn4tMhwA= -github.com/ipfs/go-unixfsnode v1.4.0/go.mod h1:qc7YFFZ8tABc58p62HnIYbUMwj9chhUuFWmxSokfePo= -github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= -github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs= -github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU= -github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o= -github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPmI+GksBlLE8js= -github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY= -github.com/ipfs/kubo v0.14.0 h1:qOmR3vd/n+ConnRiXrrLNlj4uek6S9BalMsmhG+a+u8= -github.com/ipfs/kubo v0.14.0/go.mod h1:i++XWlyJH/PpZNHI//LyoloBFUykQvcbqhmFcW6PQzY= -github.com/ipld/edelweiss v0.1.5 h1:NxsTAuaB2R+k7NweBWtUauMIRrQVjvwoyS7N9Qi+v/o= -github.com/ipld/edelweiss v0.1.5/go.mod h1:IVSfo5e7vJrTKKRjR1lrtfgc2UbEMvvatNycfH9fRfY= -github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ= -github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI= -github.com/ipld/go-car/v2 v2.4.0 h1:8jI6/iKlyLqRZzLz31jFWTqKvslaVzFsin305sOuqNQ= -github.com/ipld/go-codec-dagpb v1.3.0/go.mod h1:ga4JTU3abYApDC3pZ00BC2RSvC3qfBb9MSJkMLSwnhA= -github.com/ipld/go-codec-dagpb v1.3.1/go.mod h1:ErNNglIi5KMur/MfFE/svtgQthzVvf+43MrzLbpcIZY= -github.com/ipld/go-codec-dagpb v1.4.2 h1:fVRWHZ4w79ecVgbjy3hH4cCGIu+3QM/fQ6neTDI8C/w= -github.com/ipld/go-codec-dagpb v1.4.2/go.mod h1:JikPXjAe8GmYOJHjkz/CRJIdWE/GIXLId0w32q6RTyE= -github.com/ipld/go-ipld-prime v0.9.0/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= -github.com/ipld/go-ipld-prime v0.9.1-0.20210324083106-dc342a9917db/go.mod h1:KvBLMr4PX1gWptgkzRjVZCrLmSGcZCb/jioOQwCqZN8= -github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8= -github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM= -github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0= -github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA= -github.com/ipld/go-ipld-prime v0.17.0/go.mod h1:aYcKm5TIvGfY8P3QBKz/2gKcLxzJ1zDaD+o0bOowhgs= -github.com/ipld/go-ipld-prime v0.18.0 h1:xUk7NUBSWHEXdjiOu2sLXouFJOMs0yoYzeI5RAqhYQo= -github.com/ipld/go-ipld-prime v0.18.0/go.mod h1:735yXW548CKrLwVCYXzqx90p5deRJMVVxM9eJ4Qe+qE= -github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY= -github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA= -github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= -github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs= -github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= -github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= -github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c h1:uUx61FiAa1GI6ZmVd2wf2vULeQZIKG66eybjNXKYCz4= -github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c/go.mod h1:sdx1xVM9UuLw1tXnhJWN3piypTUO3vCIHYmG15KE/dU= -github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs= -github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= -github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY= -github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= -github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= -github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= -github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= -github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= -github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc= -github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4= github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869/go.mod h1:cJ6Cj7dQo+O6GJNiMx+Pa94qKj+TG8ONdKHgMNIyyag= -github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk= github.com/jfreymuth/oggvorbis v1.0.3 h1:MLNGGyhOMiVcvea9Dp5+gbs2SAwqwQbtrWnonYa0M0Y= @@ -804,14 +262,10 @@ github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2Q github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE= github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ= github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= 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/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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= @@ -820,49 +274,29 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm 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/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jszwec/csvutil v1.5.1/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg= -github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= 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= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/k3a/html2text v1.0.8 h1:rVanLhKilpnJUJs/CNKWzMC4YaQINGxK0rSG8ssmnV0= github.com/k3a/html2text v1.0.8/go.mod h1:ieEXykM67iT8lTvEWBh6fhpH4B23kB9OMKPdIBmgUqA= -github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0= github.com/kettek/apng v0.0.0-20220622131934-4e92eded13be h1:wghx7qCaJtHiiZb/8T2HARK/j1KeJ/BLs5fA0DItnv0= github.com/kettek/apng v0.0.0-20220622131934-4e92eded13be/go.mod h1:x78/VRQYKuCftMWS0uK5e+F5RJ7S4gSlESRWI0Prl6Q= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= -github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 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.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/koron/go-ssdp v0.0.0-20180514024734-4a0ed625a78b/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= -github.com/koron/go-ssdp v0.0.2/go.mod h1:XoLfkAiA2KeZsYh4DbHxD7h3nR2AZNqVQOa+LJuqPYs= -github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8= -github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 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/pty v1.1.3/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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -874,423 +308,15 @@ github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 h1:Bvq8AziQ5j github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042/go.mod h1:TPpsiPUEh0zFL1Snz4crhMlBe60PYxRHr5oFF3rRYg0= github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= -github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= -github.com/libp2p/go-addr-util v0.1.0/go.mod h1:6I3ZYuFr2O/9D+SoyM0zEw0EF3YkldtTX406BpdQMqw= -github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ= -github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= -github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= -github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-conn-security v0.0.1/go.mod h1:bGmu51N0KU9IEjX7kl2PQjgZa40JQWnayTvNMgD/vyk= -github.com/libp2p/go-conn-security-multistream v0.0.2/go.mod h1:nc9vud7inQ+d6SO0I/6dSWrdMnHnzZNHeyUQqrAJulE= -github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc= -github.com/libp2p/go-conn-security-multistream v0.2.0/go.mod h1:hZN4MjlNetKD3Rq5Jb/P5ohUnFLNzEAR4DLSzpn2QLU= -github.com/libp2p/go-conn-security-multistream v0.2.1/go.mod h1:cR1d8gA0Hr59Fj6NhaTpFhJZrjSYuNmhpT2r25zYR70= -github.com/libp2p/go-conn-security-multistream v0.3.0/go.mod h1:EEP47t4fw/bTelVmEzIDqSe69hO/ip52xBEhZMLWAHM= -github.com/libp2p/go-doh-resolver v0.4.0 h1:gUBa1f1XsPwtpE1du0O+nnZCUqtG7oYi7Bb+0S7FQqw= -github.com/libp2p/go-doh-resolver v0.4.0/go.mod h1:v1/jwsFusgsWIGX/c6vCRrnJ60x7bhTiq/fs2qt0cAg= -github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4= -github.com/libp2p/go-eventbus v0.2.1 h1:VanAdErQnpTioN2TowqNcOijf6YwhuODe4pPKSDpxGc= -github.com/libp2p/go-eventbus v0.2.1/go.mod h1:jc2S4SoEVPP48H9Wpzm5aiGwUCBMfGhVhhBjyhhCJs8= -github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8= -github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs= -github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= -github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.0.30/go.mod h1:XWT8FGHlhptAv1+3V/+J5mEpzyui/5bvFsNuWYs611A= -github.com/libp2p/go-libp2p v0.1.0/go.mod h1:6D/2OBauqLUoqcADOJpn9WbKqvaM07tDw68qHM0BxUM= -github.com/libp2p/go-libp2p v0.1.1/go.mod h1:I00BRo1UuUSdpuc8Q2mN7yDF/oTUTRAX6JWpTiK9Rp8= -github.com/libp2p/go-libp2p v0.6.1/go.mod h1:CTFnWXogryAHjXAKEbOf1OWY+VeAP3lDMZkfEI5sT54= -github.com/libp2p/go-libp2p v0.7.0/go.mod h1:hZJf8txWeCduQRDC/WSqBGMxaTHCOYHt2xSU1ivxn0k= -github.com/libp2p/go-libp2p v0.7.4/go.mod h1:oXsBlTLF1q7pxr+9w6lqzS1ILpyHsaBPniVO7zIHGMw= -github.com/libp2p/go-libp2p v0.8.1/go.mod h1:QRNH9pwdbEBpx5DTJYg+qxcVaDMAz3Ee/qDKwXujH5o= -github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo= -github.com/libp2p/go-libp2p v0.14.3/go.mod h1:d12V4PdKbpL0T1/gsUNN8DfgMuRPDX8bS2QxCZlwRH0= -github.com/libp2p/go-libp2p v0.14.4/go.mod h1:EIRU0Of4J5S8rkockZM7eJp2S0UrCyi55m2kJVru3rM= -github.com/libp2p/go-libp2p v0.16.0/go.mod h1:ump42BsirwAWxKzsCiFnTtN1Yc+DuPu76fyMX364/O4= -github.com/libp2p/go-libp2p v0.18.0/go.mod h1:+veaZ9z1SZQhmc5PW78jvnnxZ89Mgvmh4cggO11ETmw= -github.com/libp2p/go-libp2p v0.19.4/go.mod h1:MIt8y481VDhUe4ErWi1a4bvt/CjjFfOq6kZTothWIXY= -github.com/libp2p/go-libp2p v0.20.3 h1:tjjDNfp7FqdI/7v1rXtB/BtELaPlAThL2uzlj18kcrw= -github.com/libp2p/go-libp2p v0.20.3/go.mod h1:I+vndVanE/p/SjFbnA+BEmmfAUEpWxrdXZeyQ1Dus5c= -github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo= -github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzTdj8BXqsPR9HR0XB7I= -github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= -github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= -github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE= -github.com/libp2p/go-libp2p-autonat v0.1.0/go.mod h1:1tLf2yXxiE/oKGtDwPYWTSYG3PtvYlJmg7NeVtPRqH8= -github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE= -github.com/libp2p/go-libp2p-autonat v0.2.0/go.mod h1:DX+9teU4pEEoZUqR1PiMlqliONQdNbfzE1C718tcViI= -github.com/libp2p/go-libp2p-autonat v0.2.1/go.mod h1:MWtAhV5Ko1l6QBsHQNSuM6b1sRkXrpk0/LqCr+vCVxI= -github.com/libp2p/go-libp2p-autonat v0.2.2/go.mod h1:HsM62HkqZmHR2k1xgX34WuWDzk/nBwNHoeyyT4IWV6A= -github.com/libp2p/go-libp2p-autonat v0.4.0/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-autonat v0.4.2/go.mod h1:YxaJlpr81FhdOv3W3BTconZPfhaYivRdf53g+S2wobk= -github.com/libp2p/go-libp2p-autonat v0.6.0/go.mod h1:bFC6kY8jwzNNWoqc8iGE57vsfwyJ/lP4O4DOV1e0B2o= -github.com/libp2p/go-libp2p-blankhost v0.0.1/go.mod h1:Ibpbw/7cPPYwFb7PACIWdvxxv0t0XCCI10t7czjAjTc= -github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro= -github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU= -github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ= -github.com/libp2p/go-libp2p-blankhost v0.3.0 h1:kTnLArltMabZlzY63pgGDA4kkUcLkBFSM98zBssn/IY= -github.com/libp2p/go-libp2p-blankhost v0.3.0/go.mod h1:urPC+7U01nCGgJ3ZsV8jdwTp6Ji9ID0dMTvq+aJ+nZU= -github.com/libp2p/go-libp2p-circuit v0.0.9/go.mod h1:uU+IBvEQzCu953/ps7bYzC/D/R0Ho2A9LfKVVCatlqU= -github.com/libp2p/go-libp2p-circuit v0.1.0/go.mod h1:Ahq4cY3V9VJcHcn1SBXjr78AbFkZeIRmfunbA7pmFh8= -github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU= -github.com/libp2p/go-libp2p-circuit v0.2.1/go.mod h1:BXPwYDN5A8z4OEY9sOfr2DUQMLQvKt/6oku45YUmjIo= -github.com/libp2p/go-libp2p-circuit v0.4.0/go.mod h1:t/ktoFIUzM6uLQ+o1G6NuBl2ANhBKN9Bc8jRIk31MoA= -github.com/libp2p/go-libp2p-circuit v0.6.0 h1:rw/HlhmUB3OktS/Ygz6+2XABOmHKzZpPUuMNUMosj8w= -github.com/libp2p/go-libp2p-circuit v0.6.0/go.mod h1:kB8hY+zCpMeScyvFrKrGicRdid6vNXbunKE4rXATZ0M= -github.com/libp2p/go-libp2p-connmgr v0.2.4 h1:TMS0vc0TCBomtQJyWr7fYxcVYYhx+q/2gF++G5Jkl/w= -github.com/libp2p/go-libp2p-connmgr v0.2.4/go.mod h1:YV0b/RIm8NGPnnNWM7hG9Q38OeQiQfKhHCCs1++ufn0= -github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco= -github.com/libp2p/go-libp2p-core v0.0.2/go.mod h1:9dAcntw/n46XycV4RnlBq3BpgrmyUi9LuoTNdPrbUco= -github.com/libp2p/go-libp2p-core v0.0.3/go.mod h1:j+YQMNz9WNSkNezXOsahp9kwZBKBvxLpKD316QWSJXE= -github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I= -github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI= -github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0= -github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g= -github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA= -github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw= -github.com/libp2p/go-libp2p-core v0.3.1/go.mod h1:thvWy0hvaSBhnVBaW37BvzgVV68OUhgJJLAa6almrII= -github.com/libp2p/go-libp2p-core v0.4.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0= -github.com/libp2p/go-libp2p-core v0.5.1/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.3/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.4/go.mod h1:uN7L2D4EvPCvzSH5SrhR72UWbnSGpt5/a35Sm4upn4Y= -github.com/libp2p/go-libp2p-core v0.5.5/go.mod h1:vj3awlOr9+GMZJFH9s4mpt9RHHgGqeHCopzbYKZdRjM= -github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo= -github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.2/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8= -github.com/libp2p/go-libp2p-core v0.8.6/go.mod h1:dgHr0l0hIKfWpGpqAMbpo19pen9wJfdCGv51mTmdpmM= -github.com/libp2p/go-libp2p-core v0.9.0/go.mod h1:ESsbz31oC3C1AvMJoGx26RTuCkNhmkSRCqZ0kQtJ2/8= -github.com/libp2p/go-libp2p-core v0.10.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= -github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= -github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg= -github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8= -github.com/libp2p/go-libp2p-core v0.15.1/go.mod h1:agSaboYM4hzB1cWekgVReqV5M4g5M+2eNNejV+1EEhs= -github.com/libp2p/go-libp2p-core v0.16.1 h1:bWoiEBqVkpJ13hbv/f69tHODp86t6mvc4fBN4DkK73M= -github.com/libp2p/go-libp2p-core v0.16.1/go.mod h1:O3i/7y+LqUb0N+qhzXjBjjpchgptWAVMG1Voegk7b4c= -github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE= -github.com/libp2p/go-libp2p-crypto v0.0.2/go.mod h1:eETI5OUfBnvARGOHrJz2eWNyTUxEGZnBxMcbUjfIj4I= -github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI= -github.com/libp2p/go-libp2p-discovery v0.0.5/go.mod h1:YtF20GUxjgoKZ4zmXj8j3Nb2TUSBHFlOCetzYdbZL5I= -github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g= -github.com/libp2p/go-libp2p-discovery v0.2.0/go.mod h1:s4VGaxYMbw4+4+tsoQTqh7wfxg97AEdo4GYBt6BadWg= -github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQOu38Fu7LJGEOK2gQltw= -github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug= -github.com/libp2p/go-libp2p-discovery v0.6.0/go.mod h1:/u1voHt0tKIe5oIA1RHBKQLVCWPna2dXmPNHc2zR9S8= -github.com/libp2p/go-libp2p-discovery v0.7.0 h1:6Iu3NyningTb/BmUnEhcTwzwbs4zcywwbfTulM9LHuc= -github.com/libp2p/go-libp2p-discovery v0.7.0/go.mod h1:zPug0Rxib1aQG9iIdwOpRpBf18cAfZgzicO826UQP4I= -github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go= -github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8= -github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= -github.com/libp2p/go-libp2p-interface-connmgr v0.0.4/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= -github.com/libp2p/go-libp2p-interface-connmgr v0.0.5/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k= -github.com/libp2p/go-libp2p-interface-pnet v0.0.1/go.mod h1:el9jHpQAXK5dnTpKA4yfCNBZXvrzdOU75zz+C6ryp3k= -github.com/libp2p/go-libp2p-kad-dht v0.15.0/go.mod h1:rZtPxYu1TnHHz6n1RggdGrxUX/tA1C2/Wiw3ZMUDrU0= -github.com/libp2p/go-libp2p-kad-dht v0.16.0 h1:epVRYl3O8dn47uV3wVD2+IobEvBPapEMVj4sWlvwQHU= -github.com/libp2p/go-libp2p-kad-dht v0.16.0/go.mod h1:YYLlG8AbpWVGbI/zFeSbiGT0n0lluH7IG0sHeounyWA= -github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio= -github.com/libp2p/go-libp2p-kbucket v0.4.7 h1:spZAcgxifvFZHBD8tErvppbnNiKA5uokDu3CV7axu70= -github.com/libp2p/go-libp2p-kbucket v0.4.7/go.mod h1:XyVo99AfQH0foSf176k4jY1xUJ2+jUJIZCSDm7r2YKk= -github.com/libp2p/go-libp2p-loggables v0.0.1/go.mod h1:lDipDlBNYbpyqyPX/KcoO+eq0sJYEVR2JgOexcivchg= -github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8= -github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90= -github.com/libp2p/go-libp2p-metrics v0.0.1/go.mod h1:jQJ95SXXA/K1VZi13h52WZMa9ja78zjyy5rspMsC/08= -github.com/libp2p/go-libp2p-mplex v0.1.1/go.mod h1:KUQWpGkCzfV7UIpi8SKsAVxyBgz1c9R5EvxgnwLsb/I= -github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo= -github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE= -github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo= -github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek= -github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw= -github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g= -github.com/libp2p/go-libp2p-mplex v0.5.0/go.mod h1:eLImPJLkj3iG5t5lq68w3Vm5NAQ5BcKwrrb2VmOYb3M= -github.com/libp2p/go-libp2p-mplex v0.6.0/go.mod h1:i3usuPrBbh9FD2fLZjGpotyNkwr42KStYZQY7BeTiu4= -github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY= -github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE= -github.com/libp2p/go-libp2p-nat v0.0.6/go.mod h1:iV59LVhB3IkFvS6S6sauVTSOrNEANnINbI/fkaLimiw= -github.com/libp2p/go-libp2p-nat v0.1.0/go.mod h1:DQzAG+QbDYjN1/C3B6vXucLtz3u9rEonLVPtZVzQqks= -github.com/libp2p/go-libp2p-net v0.0.1/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= -github.com/libp2p/go-libp2p-net v0.0.2/go.mod h1:Yt3zgmlsHOgUWSXmt5V/Jpz9upuJBE8EgNU9DrCcR8c= -github.com/libp2p/go-libp2p-netutil v0.0.1/go.mod h1:GdusFvujWZI9Vt0X5BKqwWWmZFxecf9Gt03cKxm2f/Q= -github.com/libp2p/go-libp2p-netutil v0.1.0 h1:zscYDNVEcGxyUpMd0JReUZTrpMfia8PmLKcKF72EAMQ= -github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU= -github.com/libp2p/go-libp2p-noise v0.1.1/go.mod h1:QDFLdKX7nluB7DEnlVPbz7xlLHdwHFA9HiohJRr3vwM= -github.com/libp2p/go-libp2p-noise v0.2.0/go.mod h1:IEbYhBBzGyvdLBoxxULL/SGbJARhUeqlO8lVSREYu2Q= -github.com/libp2p/go-libp2p-noise v0.3.0/go.mod h1:JNjHbociDJKHD64KTkzGnzqJ0FEV5gHJa6AB00kbCNQ= -github.com/libp2p/go-libp2p-noise v0.4.0/go.mod h1:BzzY5pyzCYSyJbQy9oD8z5oP2idsafjt4/X42h9DjZU= -github.com/libp2p/go-libp2p-peer v0.0.1/go.mod h1:nXQvOBbwVqoP+T5Y5nCjeH4sP9IX/J0AMzcDUVruVoo= -github.com/libp2p/go-libp2p-peer v0.1.1/go.mod h1:jkF12jGB4Gk/IOo+yomm+7oLWxF278F7UnrYUQ1Q8es= -github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY= -github.com/libp2p/go-libp2p-peerstore v0.0.1/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= -github.com/libp2p/go-libp2p-peerstore v0.0.6/go.mod h1:RabLyPVJLuNQ+GFyoEkfi8H4Ti6k/HtZJ7YKgtSq+20= -github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY= -github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI= -github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs= -github.com/libp2p/go-libp2p-peerstore v0.2.0/go.mod h1:N2l3eVIeAitSg3Pi2ipSrJYnqhVnMNQZo9nkSCuAbnQ= -github.com/libp2p/go-libp2p-peerstore v0.2.1/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.2/go.mod h1:NQxhNjWxf1d4w6PihR8btWIRjwRLBr4TYKfNgrUkOPA= -github.com/libp2p/go-libp2p-peerstore v0.2.6/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.7/go.mod h1:ss/TWTgHZTMpsU/oKVVPQCGuDHItOpf2W8RxAi50P2s= -github.com/libp2p/go-libp2p-peerstore v0.2.8/go.mod h1:gGiPlXdz7mIHd2vfAsHzBNAMqSDkt2UBFwgcITgw1lA= -github.com/libp2p/go-libp2p-peerstore v0.4.0/go.mod h1:rDJUFyzEWPpXpEwywkcTYYzDHlwza8riYMaUzaN6hX0= -github.com/libp2p/go-libp2p-peerstore v0.6.0/go.mod h1:DGEmKdXrcYpK9Jha3sS7MhqYdInxJy84bIPtSu65bKc= -github.com/libp2p/go-libp2p-peerstore v0.7.1 h1:7FpALlqR+3+oOBXdzm3AVt0vjMYLW1b7jM03E4iEHlw= -github.com/libp2p/go-libp2p-peerstore v0.7.1/go.mod h1:cdUWTHro83vpg6unCpGUr8qJoX3e93Vy8o97u5ppIM0= -github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA= -github.com/libp2p/go-libp2p-protocol v0.0.1/go.mod h1:Af9n4PiruirSDjHycM1QuiMi/1VZNHYcK8cLgFJLZ4s= -github.com/libp2p/go-libp2p-protocol v0.1.0/go.mod h1:KQPHpAabB57XQxGrXCNvbL6UEXfQqUgC/1adR2Xtflk= -github.com/libp2p/go-libp2p-pubsub v0.6.0/go.mod h1:nJv87QM2cU0w45KPR1rZicq+FmFIOD16zmT+ep1nOmg= -github.com/libp2p/go-libp2p-pubsub v0.7.1 h1:e2CPBP5uxvDkE0FiS0obZGZPzt+xuBOc6PpG+50pIAo= -github.com/libp2p/go-libp2p-pubsub v0.7.1/go.mod h1:EuyBJFtF8qF67IEA98biwK8Xnw5MNJpJ/Z+8iWCMFwc= -github.com/libp2p/go-libp2p-pubsub-router v0.5.0 h1:WuYdY42DVIJ+N0qMdq2du/E9poJH+xzsXL7Uptwj9tw= -github.com/libp2p/go-libp2p-pubsub-router v0.5.0/go.mod h1:TRJKskSem3C0aSb3CmRgPwq6IleVFzds6hS09fmZbGM= -github.com/libp2p/go-libp2p-quic-transport v0.10.0/go.mod h1:RfJbZ8IqXIhxBRm5hqUEJqjiiY8xmEuq3HUDS993MkA= -github.com/libp2p/go-libp2p-quic-transport v0.11.2/go.mod h1:wlanzKtIh6pHrq+0U3p3DY9PJfGqxMgPaGKaK5LifwQ= -github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc= -github.com/libp2p/go-libp2p-quic-transport v0.15.0/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ= -github.com/libp2p/go-libp2p-quic-transport v0.16.0/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= -github.com/libp2p/go-libp2p-quic-transport v0.16.1/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ= -github.com/libp2p/go-libp2p-quic-transport v0.17.0/go.mod h1:x4pw61P3/GRCcSLypcQJE/Q2+E9f4X+5aRcZLXf20LM= -github.com/libp2p/go-libp2p-record v0.0.1/go.mod h1:grzqg263Rug/sRex85QrDOLntdFAymLDLm7lxMgU79Q= -github.com/libp2p/go-libp2p-record v0.1.0/go.mod h1:ujNc8iuE5dlKWVy6wuL6dd58t0n7xI4hAIl8pE6wu5Q= -github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk= -github.com/libp2p/go-libp2p-record v0.1.3 h1:R27hoScIhQf/A8XJZ8lYpnqh9LatJ5YbHs28kCIfql0= -github.com/libp2p/go-libp2p-record v0.1.3/go.mod h1:yNUff/adKIfPnYQXgp6FQmNu3gLJ6EMg7+/vv2+9pY4= -github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y= -github.com/libp2p/go-libp2p-resource-manager v0.2.1/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= -github.com/libp2p/go-libp2p-resource-manager v0.3.0 h1:2+cYxUNi33tcydsVLt6K5Fv2E3OTiVeafltecAj15E0= -github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ= -github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY= -github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw= -github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0= -github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8= -github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g= -github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8= -github.com/libp2p/go-libp2p-secio v0.2.2/go.mod h1:wP3bS+m5AUnFA+OFO7Er03uO1mncHG0uVwGrwvjYlNY= -github.com/libp2p/go-libp2p-swarm v0.0.6/go.mod h1:s5GZvzg9xXe8sbeESuFpjt8CJPTCa8mhEusweJqyFy8= -github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4= -github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU= -github.com/libp2p/go-libp2p-swarm v0.2.3/go.mod h1:P2VO/EpxRyDxtChXz/VPVXyTnszHvokHKRhfkEgFKNM= -github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM= -github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk= -github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw= -github.com/libp2p/go-libp2p-swarm v0.5.0/go.mod h1:sU9i6BoHE0Ve5SKz3y9WfKrh8dUat6JknzUehFx8xW4= -github.com/libp2p/go-libp2p-swarm v0.5.3/go.mod h1:NBn7eNW2lu568L7Ns9wdFrOhgRlkRnIDg0FLKbuu3i8= -github.com/libp2p/go-libp2p-swarm v0.8.0/go.mod h1:sOMp6dPuqco0r0GHTzfVheVBh6UEL0L1lXUZ5ot2Fvc= -github.com/libp2p/go-libp2p-swarm v0.10.0/go.mod h1:71ceMcV6Rg/0rIQ97rsZWMzto1l9LnNquef+efcRbmA= -github.com/libp2p/go-libp2p-swarm v0.10.2/go.mod h1:Pdkq0QU5a+qu+oyqIV3bknMsnzk9lnNyKvB9acJ5aZs= -github.com/libp2p/go-libp2p-swarm v0.11.0 h1:ITgsTEY2tA4OxFJGcWeugiMh2x5+VOEnI2JStT1EWxI= -github.com/libp2p/go-libp2p-swarm v0.11.0/go.mod h1:sumjVYrC84gPSZOFKL8hNcnN6HZvJSwJ8ymaXeko4Lk= -github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E= -github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0= -github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc= -github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g= -github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-testing v0.4.2/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0= -github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A= -github.com/libp2p/go-libp2p-testing v0.7.0/go.mod h1:OLbdn9DbgdMwv00v+tlp1l3oe2Cl+FAjoWIA2pa0X6E= -github.com/libp2p/go-libp2p-testing v0.8.0/go.mod h1:gRdsNxQSxAZowTgcLY7CC33xPmleZzoBpqSYbWenqPc= -github.com/libp2p/go-libp2p-testing v0.9.0/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= -github.com/libp2p/go-libp2p-testing v0.9.2 h1:dCpODRtRaDZKF8HXT9qqqgON+OMEB423Knrgeod8j84= -github.com/libp2p/go-libp2p-testing v0.9.2/go.mod h1:Td7kbdkWqYTJYQGTwzlgXwaqldraIanyjuRiAbK/XQU= -github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M= -github.com/libp2p/go-libp2p-tls v0.3.0/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= -github.com/libp2p/go-libp2p-tls v0.3.1/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY= -github.com/libp2p/go-libp2p-tls v0.4.1/go.mod h1:EKCixHEysLNDlLUoKxv+3f/Lp90O2EXNjTr0UQDnrIw= -github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk= -github.com/libp2p/go-libp2p-transport v0.0.5/go.mod h1:StoY3sx6IqsP6XKoabsPnHCwqKXWUMWU7Rfcsubee/A= -github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc= -github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA= -github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns= -github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.2/go.mod h1:NR8ne1VwfreD5VIWIU62Agt/J18ekORFU/j1i2y8zvk= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.3/go.mod h1:bpkldbOWXMrXhpZbSV1mQxTrefOg2Fi+k1ClDSA4ppw= -github.com/libp2p/go-libp2p-transport-upgrader v0.4.6/go.mod h1:JE0WQuQdy+uLZ5zOaI3Nw9dWGYJIA7mywEtP2lMvnyk= -github.com/libp2p/go-libp2p-transport-upgrader v0.5.0/go.mod h1:Rc+XODlB3yce7dvFV4q/RmyJGsFcCZRkeZMu/Zdg0mo= -github.com/libp2p/go-libp2p-transport-upgrader v0.7.0/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= -github.com/libp2p/go-libp2p-transport-upgrader v0.7.1/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg= -github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY= -github.com/libp2p/go-libp2p-xor v0.1.0 h1:hhQwT4uGrBcuAkUGXADuPltalOdpf9aag9kaYNT2tLA= -github.com/libp2p/go-libp2p-xor v0.1.0/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQJscoIL/u6InY= -github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8= -github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4= -github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8= -github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI= -github.com/libp2p/go-libp2p-yamux v0.2.2/go.mod h1:lIohaR0pT6mOt0AZ0L2dFze9hds9Req3OfS+B+dv4qw= -github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ48OpsfmQVTErwA= -github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU= -github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4= -github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30= -github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po= -github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4= -github.com/libp2p/go-libp2p-yamux v0.5.4/go.mod h1:tfrXbyaTqqSU654GTvK3ocnSZL3BuHoeTSqhcel1wsE= -github.com/libp2p/go-libp2p-yamux v0.6.0/go.mod h1:MRhd6mAYnFRnSISp4M8i0ClV/j+mWHo2mYLifWGw33k= -github.com/libp2p/go-libp2p-yamux v0.8.0/go.mod h1:yTkPgN2ib8FHyU1ZcVD7aelzyAqXXwEPbyx+aSKm9h8= -github.com/libp2p/go-libp2p-yamux v0.8.1/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= -github.com/libp2p/go-libp2p-yamux v0.8.2/go.mod h1:rUozF8Jah2dL9LLGyBaBeTQeARdwhefMCTQVQt6QobE= -github.com/libp2p/go-libp2p-yamux v0.9.1/go.mod h1:wRc6wvyxQINFcKe7daL4BeQ02Iyp+wxyC8WCNfngBrA= -github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q= -github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M= -github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU= -github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0= -github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU= -github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk= -github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ= -github.com/libp2p/go-mplex v0.4.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= -github.com/libp2p/go-mplex v0.6.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E= -github.com/libp2p/go-mplex v0.7.0 h1:BDhFZdlk5tbr0oyFq/xv/NPGfjbnrsDam1EvutpBDbY= -github.com/libp2p/go-mplex v0.7.0/go.mod h1:rW8ThnRcYWft/Jb2jeORBmPd6xuG3dGxWN/W168L9EU= -github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ= -github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA= -github.com/libp2p/go-msgio v0.1.0/go.mod h1:eNlv2vy9V2X/kNldcZ+SShFE++o2Yjxwx6RAYsmgJnE= -github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU= -github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY= -github.com/libp2p/go-nat v0.0.3/go.mod h1:88nUEt0k0JD45Bk93NIwDqjlhiOwOoV36GchpcVc1yI= -github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo= -github.com/libp2p/go-nat v0.0.5/go.mod h1:B7NxsVNPZmRLvMOwiEO1scOSyjA56zxYAGv1yQgRkEU= -github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= -github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= -github.com/libp2p/go-netroute v0.1.5/go.mod h1:V1SR3AaECRkEQCoFFzYwVYWvYIEtlxx89+O3qcpCl4A= -github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ= -github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE= -github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= -github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0= -github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw= -github.com/libp2p/go-openssl v0.0.7/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc= -github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA= -github.com/libp2p/go-reuseport v0.0.2/go.mod h1:SPD+5RwGC7rcnzngoYC86GjPzjSywuQyMVAheVBD9nQ= -github.com/libp2p/go-reuseport v0.1.0/go.mod h1:bQVn9hmfcTaoo0c9v5pBhOarsU1eNOBZdaAd2hzXRKU= -github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= -github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k= -github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs= -github.com/libp2p/go-reuseport-transport v0.0.3/go.mod h1:Spv+MPft1exxARzP2Sruj2Wb5JSyHNncjf1Oi2dEbzM= -github.com/libp2p/go-reuseport-transport v0.0.4/go.mod h1:trPa7r/7TJK/d+0hdBLOCGvpQQVOU74OXbNCIMkufGw= -github.com/libp2p/go-reuseport-transport v0.0.5/go.mod h1:TC62hhPc8qs5c/RoXDZG6YmjK+/YWUPC0yYmeUecbjc= -github.com/libp2p/go-reuseport-transport v0.1.0/go.mod h1:vev0C0uMkzriDY59yFHD9v+ujJvYmDQVLowvAjEOmfw= -github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= -github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14= -github.com/libp2p/go-stream-muxer v0.1.0/go.mod h1:8JAVsjeRBCWwPoZeH0W1imLOcriqXJyFvB0mR4A04sQ= -github.com/libp2p/go-stream-muxer-multistream v0.1.1/go.mod h1:zmGdfkQ1AzOECIAcccoL8L//laqawOsO03zX8Sa+eGw= -github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc= -github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA= -github.com/libp2p/go-stream-muxer-multistream v0.4.0/go.mod h1:nb+dGViZleRP4XcyHuZSVrJCBl55nRBOMmiSL/dyziw= -github.com/libp2p/go-tcp-transport v0.0.4/go.mod h1:+E8HvC8ezEVOxIo3V5vCK9l1y/19K427vCzQ+xHKH/o= -github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc= -github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY= -github.com/libp2p/go-tcp-transport v0.2.0/go.mod h1:vX2U0CnWimU4h0SGSEsg++AzvBcroCGYw28kh94oLe0= -github.com/libp2p/go-tcp-transport v0.2.1/go.mod h1:zskiJ70MEfWz2MKxvFB/Pv+tPIB1PpPUrHIWQ8aFw7M= -github.com/libp2p/go-tcp-transport v0.2.3/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= -github.com/libp2p/go-tcp-transport v0.2.4/go.mod h1:9dvr03yqrPyYGIEN6Dy5UvdJZjyPFvl1S/igQ5QD1SU= -github.com/libp2p/go-tcp-transport v0.2.7/go.mod h1:lue9p1b3VmZj1MhhEGB/etmvF/nBQ0X9CW2DutBT3MM= -github.com/libp2p/go-tcp-transport v0.4.0/go.mod h1:0y52Rwrn4076xdJYu/51/qJIdxz+EWDAOG2S45sV3VI= -github.com/libp2p/go-tcp-transport v0.5.0/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= -github.com/libp2p/go-tcp-transport v0.5.1/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y= -github.com/libp2p/go-testutil v0.0.1/go.mod h1:iAcJc/DKJQanJ5ws2V+u5ywdL2n12X1WbbEG+Jjy69I= -github.com/libp2p/go-testutil v0.1.0/go.mod h1:81b2n5HypcVyrCg/MJx4Wgfp/VHojytjVe/gLzZ2Ehc= -github.com/libp2p/go-ws-transport v0.0.5/go.mod h1:Qbl4BxPfXXhhd/o0wcrgoaItHqA9tnZjoFZnxykuaXU= -github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw7yT74kj3raBFuo= -github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM= -github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk= -github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA= -github.com/libp2p/go-ws-transport v0.5.0/go.mod h1:I2juo1dNTbl8BKSBYo98XY85kU2xds1iamArLvl8kNg= -github.com/libp2p/go-ws-transport v0.6.0/go.mod h1:dXqtI9e2JV9FtF1NOtWVZSKXh5zXvnuwPXfj8GPBbYU= -github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.0/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.5/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow= -github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE= -github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U= -github.com/libp2p/go-yamux/v2 v2.2.0/go.mod h1:3So6P6TV6r75R9jiBpiIKgU/66lOarCZjqROGxzPpPQ= -github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs= -github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= -github.com/libp2p/go-yamux/v3 v3.0.2/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo= -github.com/libp2p/go-yamux/v3 v3.1.1/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= -github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q= -github.com/libp2p/go-yamux/v3 v3.1.2/go.mod h1:jeLEQgLXqE2YqX1ilAClIfCMDY+0uXQUKmmb/qp0gT4= -github.com/libp2p/zeroconf/v2 v2.1.1 h1:XAuSczA96MYkVwH+LqqqCUZb2yH3krobMJ1YE+0hG2s= -github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lucas-clemente/quic-go v0.19.3/go.mod h1:ADXpNbTQjq1hIzCpB+y/k5iz4n4z4IwqoLb94Kh5Hu8= -github.com/lucas-clemente/quic-go v0.21.2/go.mod h1:vF5M1XqhBAHgbjKcJOXY3JZz3GP0T3FQhz/uyOUS38Q= -github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= -github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0= -github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg= -github.com/lucas-clemente/quic-go v0.27.0/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= -github.com/lucas-clemente/quic-go v0.27.1 h1:sOw+4kFSVrdWOYmUjufQ9GBVPqZ+tu+jMtXxXNmRJyk= -github.com/lucas-clemente/quic-go v0.27.1/go.mod h1:AzgQoPda7N+3IqMMMkywBKggIFo2KT6pfnlrQ2QieeI= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= -github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/marten-seemann/qpack v0.2.1/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= -github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= -github.com/marten-seemann/qtls-go1-15 v0.1.1/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= -github.com/marten-seemann/qtls-go1-15 v0.1.4/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= -github.com/marten-seemann/qtls-go1-15 v0.1.5/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= -github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= -github.com/marten-seemann/qtls-go1-16 v0.1.5/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk= -github.com/marten-seemann/qtls-go1-17 v0.1.0-rc.1/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= -github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8= -github.com/marten-seemann/qtls-go1-17 v0.1.1/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= -github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ= -github.com/marten-seemann/qtls-go1-17 v0.1.2/go.mod h1:C2ekUKcDdz9SDWxec1N/MvcXBpaX9l3Nx67XaR84L5s= -github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI= -github.com/marten-seemann/qtls-go1-18 v0.1.1/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM= -github.com/marten-seemann/qtls-go1-18 v0.1.2/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= -github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -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-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -1301,47 +327,18 @@ github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA= github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77 h1:DDyKVkTkrFmd9lR84QW3EIfkkoHlurlpgW+DYuAUJn8= github.com/mewkiz/pkg v0.0.0-20211102230744-16a6ce8f1b77/go.mod h1:J/rDzvIiwiVpv72OEP8aJFxLXjGpUdviIIeqJPLIctA= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.28/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= -github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= -github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= -github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= -github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= -github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= -github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v6 v6.0.57 h1:ixPkbKkyD7IhnluRgQpGSpHdpvNVaW6OD5R9IAO/9Tw= github.com/minio/minio-go/v6 v6.0.57/go.mod h1:5+R/nM9Pwrh0vqF+HbYYDQ84wdUFPyXHkrdT4AIkifM= -github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -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= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1349,528 +346,112 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= -github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= -github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= -github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= -github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= -github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= -github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE= -github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y= -github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI= -github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc= -github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0= -github.com/multiformats/go-multiaddr v0.4.0/go.mod h1:YcpyLH8ZPudLxQlemYBPhSm0/oCXAT8Z4mzFpyoPyRc= -github.com/multiformats/go-multiaddr v0.4.1/go.mod h1:3afI9HfVW8csiF8UZqtpYRiDyew8pRX7qLIGHu9FLuM= -github.com/multiformats/go-multiaddr v0.5.0/go.mod h1:3KAxNkUqLTJ20AAwN4XVX4kZar+bR+gh4zgbfr3SNug= -github.com/multiformats/go-multiaddr v0.6.0 h1:qMnoOPj2s8xxPU5kZ57Cqdr0hHhARz7mFsPMIiYNqzg= -github.com/multiformats/go-multiaddr v0.6.0/go.mod h1:F4IpaKZuPP360tOMn2Tpyu0At8w23aRyVqeK0DbFeGM= -github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q= -github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0= -github.com/multiformats/go-multiaddr-dns v0.3.0/go.mod h1:mNzQ4eTGDg0ll1N9jKPOUogZPoJ30W8a7zk66FQPpdQ= -github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= -github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= -github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU= -github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ= -github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y= -github.com/multiformats/go-multiaddr-net v0.1.3/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.4/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.1.5/go.mod h1:ilNnaM9HbmVFqsb/qcNysjCu4PVONlrBZpHIrw/qQuA= -github.com/multiformats/go-multiaddr-net v0.2.0/go.mod h1:gGdH3UXny6U3cKKYCvpXI5rnK7YaOIEOPVDI9tsJbEA= -github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= -github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= -github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI= -github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8= -github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErhycTIftytRV+llXdyS4= -github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ= -github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= -github.com/multiformats/go-multicodec v0.3.1-0.20211210143421-a526f306ed2c/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= -github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ= -github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs= -github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues= -github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= -github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= -github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg= -github.com/multiformats/go-multihash v0.0.16/go.mod h1:zhfEIgVnB/rPMfxgFw15ZmGoNaKyNUIE4IWHG/kC+Ag= -github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84= -github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= -github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= -github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.0.4/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg= -github.com/multiformats/go-multistream v0.1.1/go.mod h1:KmHZ40hzVxiaiwlj3MEbYgK9JFk2/9UktWZAF54Du38= -github.com/multiformats/go-multistream v0.2.0/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-multistream v0.2.1/go.mod h1:5GZPQZbkWOLOn3J2y4Y99vVW7vOfsAflxARk3x14o6k= -github.com/multiformats/go-multistream v0.2.2/go.mod h1:UIcnm7Zuo8HKG+HkWgfQsGL+/MIEhyTqbODbIUwSXKs= -github.com/multiformats/go-multistream v0.3.0/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= -github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o= -github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.2/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= -github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= -github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/olebedev/emitter v0.0.0-20190110104742-e8d1457e6aee h1:IquUs3fIykn10zWDIyddanhpTqBvAHMaPnFhQuyYw5U= github.com/olebedev/emitter v0.0.0-20190110104742-e8d1457e6aee/go.mod h1:eT2/Pcsim3XBjbvldGiJBvvgiqZkAFyiOJJsDKXs/ts= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= -github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= -github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= -github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/openzipkin/zipkin-go v0.4.0 h1:CtfRrOVZtbDj8rt1WXjklw0kqqJQwICrCKmlfUuBUUw= -github.com/openzipkin/zipkin-go v0.4.0/go.mod h1:4c3sLeE8xjNqehmF5RpAFLPLJxXscc0R4l6Zg0P1tTQ= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= -github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+Tv1WTxkukpXeMlviSxvL7SRgk= -github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/peterbourgon/g2s v0.0.0-20170223122336-d4e7ad98afea h1:sKwxy1H95npauwu8vtF95vG/syrL0p8fSZo/XlDg5gk= github.com/peterbourgon/g2s v0.0.0-20170223122336-d4e7ad98afea/go.mod h1:1VcHEd3ro4QMoHfiNl/j7Jkln9+KQuorp0PItHMJYNg= -github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= 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/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= -github.com/polydawn/refmt v0.0.0-20190408063855-01bf1e26dd14/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= -github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= -github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls= -github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= -github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.33.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/rabbitmq/amqp091-go v1.1.0/go.mod h1:ogQDLSOACsLPsIq0NpbtiifNZi2YOz0VTJ0kHRghqbM= -github.com/raulk/clock v1.1.0/go.mod h1:3MpVxdZ/ODBQDxbN+kzshf5OSZwPjtMDx6BBXBmOeY0= -github.com/raulk/go-watchdog v1.2.0/go.mod h1:lzSbAl5sh4rtI8tYHU01BWIDzgzqaQLj6RcA1i4mlqI= -github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= -github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo= github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= -github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM= github.com/rubyist/circuitbreaker v2.2.1+incompatible h1:KUKd/pV8Geg77+8LNDwdow6rVCAYOp8+kHUyFvL6Mhk= github.com/rubyist/circuitbreaker v2.2.1+incompatible/go.mod h1:Ycs3JgJADPuzJDwffe12k6BZT8hxVi6lFK+gWYJLN4A= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+uQBDeAhHhwdzB5fSlVdhGcM= github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= -github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= -github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= -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/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= -github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= -github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= -github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= -github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= -github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= -github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= -github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= -github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= -github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= -github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= -github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= -github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= -github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= -github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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= -github.com/smartystreets/goconvey v0.0.0-20190222223459-a17d461953aa/go.mod h1:2RVY1rIf+2J2o/IM9+vPq9RzmHDSseB7FoXiSNIUsoU= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= -github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= -github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= -github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc= -github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= -github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto= github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= -github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= -github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ= -github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= -github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= -github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= -github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/wI2L/jsondiff v0.2.0 h1:dE00WemBa1uCjrzQUUTE/17I6m5qAaN0EMFOg2Ynr/k= -github.com/wI2L/jsondiff v0.2.0/go.mod h1:axTcwtBkY4TsKuV+RgoMhHyHKKFRI6nnjRLi8LLYQnA= -github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= -github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= -github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= -github.com/warpfork/go-testmark v0.10.0 h1:E86YlUMYfwIacEsQGlnTvjk1IgYkyTGjPhF0RnwTCmw= -github.com/warpfork/go-testmark v0.10.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= -github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= -github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w= -github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= -github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= -github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc/go.mod h1:r45hJU7yEoA81k6MWNhpMj/kms0n14dkzkxYHoB96UM= -github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= -github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158/go.mod h1:Xj/M2wWU+QdTdRbu/L/1dIZY8/Wb2K9pAhtroQuxJJI= -github.com/whyrusleeping/cbor-gen v0.0.0-20200710004633-5379fc63235d/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c h1:6VPKXBDRt7mDUyiHx9X8ROnPYFDf3L7OfEuKCI5dZDI= -github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= -github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= -github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc= -github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= -github.com/whyrusleeping/go-logging v0.0.1/go.mod h1:lDPYj54zutzG1XYfHAhcc7oNXEburHQBn+Iqd4yS4vE= -github.com/whyrusleeping/go-notifier v0.0.0-20170827234753-097c5d47330f/go.mod h1:cZNvX9cFybI01GriPRMXDtczuvUhgbcYr9iCGaNlRv8= -github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA= -github.com/whyrusleeping/mdns v0.0.0-20180901202407-ef14215e6b30/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= -github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds= -github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI= -github.com/whyrusleeping/tar-utils v0.0.0-20180509141711-8c6c8ba81d5c/go.mod h1:xxcJeBb7SIUl/Wzkz1eVKJE/CB34YNrqX2TQI6jY9zs= -github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b h1:wA3QeTsaAXybLL2kb2cKhCAQTHgYTMwuI8lBlJSv5V8= -github.com/whyrusleeping/tar-utils v0.0.0-20201201191210-20a61371de5b/go.mod h1:xT1Y5p2JR2PfSZihE0s4mjdJaRGp1waCTf5JzhQLBck= -github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee h1:lYbXeSvJi5zk5GLKVuid9TVjS9a0OmLIDKTfoZBL6Ow= -github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee/go.mod h1:m2aV4LZI4Aez7dP5PMyVKEHhUyEJ/RjmPEDOpDvudHg= -github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= 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.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel v1.2.0/go.mod h1:aT17Fk0Z1Nor9e0uisf98LrntPGMnk4frBO9+dkf69I= -go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= -go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= -go.opentelemetry.io/otel v1.9.0 h1:8WZNQFIB2a71LnANS9JeyidJKKGOOremcUtb/OtHISw= -go.opentelemetry.io/otel v1.9.0/go.mod h1:np4EoPGzoPs3O67xUVNoPPcmSvsfOxNlNA4F4AC+0Eo= -go.opentelemetry.io/otel/exporters/jaeger v1.9.0 h1:gAEgEVGDWwFjcis9jJTOJqZNxDzoZfR12WNIxr7g9Ww= -go.opentelemetry.io/otel/exporters/jaeger v1.9.0/go.mod h1:hquezOLVAybNW6vanIxkdLXTXvzlj2Vn3wevSP15RYs= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0 h1:ggqApEjDKczicksfvZUCxuvoyDmR6Sbm56LwiK8DVR0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.9.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 h1:NN90Cuna0CnBg8YNu1Q0V35i2E8LDByFOwHRCq/ZP9I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0/go.mod h1:0EsCXjZAiiZGnLdEUXM9YjCKuuLZMYyglh2QDXcYKVA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.9.0 h1:M0/hqGuJBLeIEu20f89H74RGtqV2dn+SFWEz9ATAAwY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.9.0/go.mod h1:K5G92gbtCrYJ0mn6zj9Pst7YFsDFuvSYEhYKRMcufnM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0 h1:FAF9l8Wjxi9Ad2k/vLTfHZyzXYX72C62wBGpV3G6AIo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0/go.mod h1:smUdtylgc0YQiUr2PuifS4hBXhAS5xtR6WQhxP1wiNA= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.9.0 h1:0uV0qzHk48i1SF8qRI8odMYiwPOLh9gBhiJFpj8H6JY= -go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.9.0/go.mod h1:Fl1iS5ZhWgXXXTdJMuBSVsS5nkL5XluHbg97kjOuYU4= -go.opentelemetry.io/otel/exporters/zipkin v1.9.0 h1:06b/nt6xao6th00aue9WU3ZDTTe+InaMXA/vym6pLuA= -go.opentelemetry.io/otel/exporters/zipkin v1.9.0/go.mod h1:HyIvYIu37wV4Wx5azd7e05x9k/dOz9KB4x0plw2QNvs= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk v1.2.0/go.mod h1:jNN8QtpvbsKhgaC6V5lHiejMoKD+V8uadoSafgHPx1U= -go.opentelemetry.io/otel/sdk v1.9.0 h1:LNXp1vrr83fNXTHgU8eO89mhzxb/bbWAsHG6fNf3qWo= -go.opentelemetry.io/otel/sdk v1.9.0/go.mod h1:AEZc8nt5bd2F7BC24J5R0mrjYnpEgYHyTcM/vrSple4= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/otel/trace v1.2.0/go.mod h1:N5FLswTubnxKxOJHM7XZC074qpeEdLy3CgAVsdMucK0= -go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= -go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= -go.opentelemetry.io/otel/trace v1.9.0 h1:oZaCNJUjWcg60VXWee8lJKlqhPbXAPB51URuR47pQYc= -go.opentelemetry.io/otel/trace v1.9.0/go.mod h1:2737Q0MuG8q1uILYm2YYVkAyLtOofiTNGg6VODnOiPo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -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/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/dig v1.15.0 h1:vq3YWr8zRj1eFGC7Gvf907hE0eRjPTZ1d3xHadD6liE= -go.uber.org/dig v1.15.0/go.mod h1:pKHs0wMynzL6brANhB2hLMro+zalv1osARTviTcqHLM= -go.uber.org/fx v1.18.1 h1:I7VWkdv4iKcbpH7KVSi9Fe1LGmpJv+pbBIb9NidPb+E= -go.uber.org/fx v1.18.1/go.mod h1:g0V1KMQ66zIRk8bLu3Ea5Jt2w/cHlOIp4wdRsgh0JaY= -go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -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.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/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.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.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -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= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= -go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= -go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= -go4.org v0.0.0-20201209231011-d4a079459e60 h1:iqAGo78tVOJXELHQFRjR6TMwItrvXH4hrGJ32I/NFF8= -go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= -golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= -golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/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= -golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200423211502-4bdfaf469ed5/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/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/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-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210920023735-84f357641f63/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-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/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= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= @@ -1878,15 +459,12 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20210615023648-acb5c1269671 h1:ddvpKwqE7dm58PoWjRCmaCiA3DANEW0zWGfNYQD212Y= -golang.org/x/exp v0.0.0-20210615023648-acb5c1269671/go.mod h1:DVyR6MI7P4kEQgvZJSj1fQGrWIi2RzIrfYWycwheUAc= golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU= golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1900,47 +478,27 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190611141213-3f473d35a33a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1952,47 +510,26 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/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-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210917221730-978cfadd31cf/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-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220517181318-183a9ca12b87/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= 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= @@ -2003,59 +540,27 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190302025703-b6889370fb10/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190524122548-abf6ff778158/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190524152521-dbbf3f1254d4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190526052359-791d8a0f4d09/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190610200419-93c9922d18ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2065,47 +570,28 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210317225723-c4fcb01b228e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/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-20210603081109-ebe580a85c40/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-20210630005230-0f9fa26af87c/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-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-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/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= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc= @@ -2115,22 +601,15 @@ 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= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/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-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -2146,19 +625,13 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -2170,35 +643,18 @@ golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200423201157-2723c5de0d66/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/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.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.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= @@ -2216,23 +672,16 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -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= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= -google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= 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-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= @@ -2258,37 +707,22 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959 h1:hw4Y42zL1VyVKxPgRHHh191fpVBGV8sNVmcow5Z8VXY= google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= 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.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -2304,7 +738,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -2313,40 +746,23 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8= -gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE= 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= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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= -grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2355,15 +771,6 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -lukechampine.com/blake3 v1.1.6/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= -pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= -pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= -sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= -sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/ipfs_proxy/api.go b/ipfs_proxy/api.go deleted file mode 100644 index 3ce24393c54a12d810a80f1b19ffc01a1f7a4862..0000000000000000000000000000000000000000 --- a/ipfs_proxy/api.go +++ /dev/null @@ -1,69 +0,0 @@ -package ipfs_proxy - -import ( - "github.com/getsentry/sentry-go" - "io" - - "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/common/config" - "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/ipfs_proxy/ipfs_embedded" - "github.com/turt2live/matrix-media-repo/ipfs_proxy/ipfs_local" - "github.com/turt2live/matrix-media-repo/ipfs_proxy/ipfs_models" -) - -var implementation IPFSImplementation - -func Reload() { - if implementation != nil { - implementation.Stop() - } - implementation = nil - - if !config.Get().Features.IPFS.Enabled { - return - } - - if config.Get().Features.IPFS.Daemon.Enabled { - logrus.Info("Starting up local IPFS daemon...") - impl, err := ipfs_embedded.NewEmbeddedIPFSNode() - if err != nil { - sentry.CaptureException(err) - panic(err) - } - implementation = impl - } else { - logrus.Info("Using localhost IPFS HTTP agent...") - impl, err := ipfs_local.NewLocalIPFSImplementation() - if err != nil { - sentry.CaptureException(err) - panic(err) - } - implementation = impl - } -} - -func Stop() { - if implementation != nil { - implementation.Stop() - } - implementation = nil -} - -func getImpl() IPFSImplementation { - if implementation == nil { - Reload() - } - if implementation == nil { - panic("missing ipfs implementation object") - } - return implementation -} - -func GetObject(contentId string, ctx rcontext.RequestContext) (*ipfs_models.IPFSObject, error) { - return getImpl().GetObject(contentId, ctx) -} - -func PutObject(data io.Reader, ctx rcontext.RequestContext) (string, error) { - return getImpl().PutObject(data, ctx) -} diff --git a/ipfs_proxy/iface.go b/ipfs_proxy/iface.go deleted file mode 100644 index e80a55189c8001de2f36f9a754dc345e2b987d9c..0000000000000000000000000000000000000000 --- a/ipfs_proxy/iface.go +++ /dev/null @@ -1,14 +0,0 @@ -package ipfs_proxy - -import ( - "io" - - "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/ipfs_proxy/ipfs_models" -) - -type IPFSImplementation interface { - GetObject(contentId string, ctx rcontext.RequestContext) (*ipfs_models.IPFSObject, error) - PutObject(data io.Reader, ctx rcontext.RequestContext) (string, error) - Stop() -} diff --git a/ipfs_proxy/ipfs_embedded/impl.go b/ipfs_proxy/ipfs_embedded/impl.go deleted file mode 100644 index b84473b4daa52ca17cc484f8879988d52f668f4e..0000000000000000000000000000000000000000 --- a/ipfs_proxy/ipfs_embedded/impl.go +++ /dev/null @@ -1,167 +0,0 @@ -package ipfs_embedded - -import ( - "bytes" - "context" - "io" - "io/ioutil" - "path" - "path/filepath" - "time" - - "github.com/ipfs/go-cid" - files "github.com/ipfs/go-ipfs-files" - icore "github.com/ipfs/interface-go-ipfs-core" - icorepath "github.com/ipfs/interface-go-ipfs-core/path" - ipfsConfig "github.com/ipfs/kubo/config" - "github.com/ipfs/kubo/core" - "github.com/ipfs/kubo/core/bootstrap" - "github.com/ipfs/kubo/core/coreapi" - "github.com/ipfs/kubo/core/node/libp2p" - "github.com/ipfs/kubo/plugin/loader" - "github.com/ipfs/kubo/repo/fsrepo" - "github.com/sirupsen/logrus" - "github.com/turt2live/matrix-media-repo/common/config" - "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/ipfs_proxy/ipfs_models" - "github.com/turt2live/matrix-media-repo/util" -) - -type IPFSEmbedded struct { - api icore.CoreAPI - node *core.IpfsNode - ctx context.Context - cancelCtxFn context.CancelFunc -} - -func NewEmbeddedIPFSNode() (IPFSEmbedded, error) { - // Startup routine modified from: - // https://github.com/ipfs/kubo/blob/083ef47ce84a5bd9a93f0ce0afaf668881dc1f35/docs/examples/go-ipfs-as-a-library/main.go - - basePath := config.Get().Features.IPFS.Daemon.RepoPath - dataPath := path.Join(basePath, "data") - - ctx, cancel := context.WithCancel(context.Background()) - - blank := IPFSEmbedded{} - - // Load plugins - logrus.Info("Loading plugins for IPFS embedded node...") - plugins, err := loader.NewPluginLoader(filepath.Join(basePath, "plugins")) - if err != nil { - cancel() - return blank, err - } - err = plugins.Initialize() - if err != nil { - cancel() - return blank, err - } - err = plugins.Inject() - if err != nil { - cancel() - return blank, err - } - - logrus.Info("Generating config for IPFS embedded node") - cfg, err := ipfsConfig.Init(ioutil.Discard, 2048) - if err != nil { - cancel() - return blank, err - } - - logrus.Info("Initializing IPFS embedded node") - err = fsrepo.Init(dataPath, cfg) - if err != nil { - cancel() - return blank, err - } - - logrus.Info("Starting fsrepo for IPFS embedded node") - repo, err := fsrepo.Open(dataPath) - if err != nil { - cancel() - return blank, err - } - - // Create the node from the repo - nodeOptions := &core.BuildCfg{ - Online: true, - Routing: libp2p.DHTOption, - Repo: repo, - } - - logrus.Info("Building IPFS embedded node") - node, err := core.NewNode(ctx, nodeOptions) - if err != nil { - cancel() - return blank, err - } - - logrus.Info("Generating API reference for IPFS embedded node") - api, err := coreapi.NewCoreAPI(node) - if err != nil { - cancel() - return blank, err - } - - // Connect to peers so we can actually get started - logrus.Info("Connecting to peers for IPFS embedded node") - err = node.Bootstrap(bootstrap.DefaultBootstrapConfig) - if err != nil { - cancel() - return blank, err - } - - logrus.Info("Done building IPFS embedded node") - return IPFSEmbedded{ - api: api, - node: node, - ctx: ctx, - cancelCtxFn: cancel, - }, nil -} - -func (i IPFSEmbedded) GetObject(contentId string, ctx rcontext.RequestContext) (*ipfs_models.IPFSObject, error) { - ctx.Log.Info("Getting object from embedded IPFS node") - ipfsCid, err := cid.Decode(contentId) - if err != nil { - return nil, err - } - - ctx.Log.Info("Resolving path and node") - timeoutCtx, cancel := context.WithTimeout(ctx.Context, 10*time.Second) - defer cancel() - ipfsPath := icorepath.IpfsPath(ipfsCid) - r, err := i.api.Object().Data(timeoutCtx, ipfsPath) - if err != nil { - return nil, err - } - - b, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - ctx.Log.Info("Returning object") - return &ipfs_models.IPFSObject{ - ContentType: "application/octet-stream", // TODO: Actually fetch - FileName: "ipfs.dat", // TODO: Actually fetch - SizeBytes: int64(len(b)), - Data: util.BufferToStream(bytes.NewBuffer(b)), // stream to avoid log spam - }, nil -} - -func (i IPFSEmbedded) PutObject(data io.Reader, ctx rcontext.RequestContext) (string, error) { - ipfsFile := files.NewReaderFile(data) - p, err := i.api.Unixfs().Add(ctx.Context, ipfsFile) - if err != nil { - return "", err - } - return p.Cid().String(), nil -} - -func (i IPFSEmbedded) Stop() { - i.cancelCtxFn() - _ = i.node.Close() -} diff --git a/ipfs_proxy/ipfs_local/impl.go b/ipfs_proxy/ipfs_local/impl.go deleted file mode 100644 index 528221f643c19209206fc6c996b2ceb45f144d86..0000000000000000000000000000000000000000 --- a/ipfs_proxy/ipfs_local/impl.go +++ /dev/null @@ -1,61 +0,0 @@ -package ipfs_local - -import ( - "bytes" - "io" - "io/ioutil" - - "github.com/ipfs/go-cid" - httpapi "github.com/ipfs/go-ipfs-api" - "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/ipfs_proxy/ipfs_models" - "github.com/turt2live/matrix-media-repo/util" -) - -type IPFSLocal struct { - client *httpapi.Shell -} - -func NewLocalIPFSImplementation() (IPFSLocal, error) { - client := httpapi.NewLocalShell() - return IPFSLocal{ - client: client, - }, nil -} - -func (i IPFSLocal) GetObject(contentId string, ctx rcontext.RequestContext) (*ipfs_models.IPFSObject, error) { - ipfsCid, err := cid.Decode(contentId) - if err != nil { - return nil, err - } - - c, err := i.client.Cat(ipfsCid.String()) - if err != nil { - return nil, err - } - defer c.Close() - - b, err := ioutil.ReadAll(c) - if err != nil { - return nil, err - } - - return &ipfs_models.IPFSObject{ - ContentType: "application/octet-stream", // TODO: Actually fetch - FileName: "ipfs.dat", // TODO: Actually fetch - SizeBytes: int64(len(b)), - Data: util.BufferToStream(bytes.NewBuffer(b)), // stream to avoid log spam - }, nil -} - -func (i IPFSLocal) PutObject(data io.Reader, ctx rcontext.RequestContext) (string, error) { - p, err := i.client.Add(data) - if err != nil { - return "", err - } - return p, nil -} - -func (i IPFSLocal) Stop() { - // Nothing to do -} diff --git a/ipfs_proxy/ipfs_models/object.go b/ipfs_proxy/ipfs_models/object.go deleted file mode 100644 index cf79a801205488426a47101e78348bccb0181040..0000000000000000000000000000000000000000 --- a/ipfs_proxy/ipfs_models/object.go +++ /dev/null @@ -1,12 +0,0 @@ -package ipfs_models - -import ( - "io" -) - -type IPFSObject struct { - ContentType string - FileName string - SizeBytes int64 - Data io.ReadCloser -} diff --git a/matrix/client_server.go b/matrix/client_server.go index 7e20e62ab0dd977a5e16d35846fbf17be2f72975..cf70d451a465a2e2e87c06785dcb68dafa89cbd0 100644 --- a/matrix/client_server.go +++ b/matrix/client_server.go @@ -10,7 +10,7 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/util/cleanup" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) // Based in part on https://github.com/matrix-org/gomatrix/blob/072b39f7fa6b40257b4eead8c958d71985c28bdd/client.go#L180-L243 @@ -48,7 +48,7 @@ func doRequest(ctx rcontext.RequestContext, method string, urlStr string, body i if err != nil { return err } - defer cleanup.DumpAndCloseStream(res.Body) + defer stream_util.DumpAndCloseStream(res.Body) contents, err := ioutil.ReadAll(res.Body) if err != nil { diff --git a/metrics/listeners.go b/metrics/listeners.go deleted file mode 100644 index e757165b69ea1bbcb8029404181ccb47d13c5eda..0000000000000000000000000000000000000000 --- a/metrics/listeners.go +++ /dev/null @@ -1,7 +0,0 @@ -package metrics - -var beforeMetricsCalledFns = make([]func(), 0) - -func OnBeforeMetricsRequested(fn func()) { - beforeMetricsCalledFns = append(beforeMetricsCalledFns, fn) -} diff --git a/metrics/webserver.go b/metrics/webserver.go index 90ddf1c46a95d7ad3d1d7f0c0326f3a2322bc3c1..d3ddfd3e043d4ae0b59f7cc7107bcdd1a68e9563 100644 --- a/metrics/webserver.go +++ b/metrics/webserver.go @@ -2,12 +2,13 @@ package metrics import ( "context" - "github.com/getsentry/sentry-go" "net" "net/http" "strconv" "time" + "github.com/getsentry/sentry-go" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common/config" @@ -16,10 +17,6 @@ import ( var srv *http.Server func internalHandler(res http.ResponseWriter, req *http.Request) { - logrus.Info("Updating live metrics for cache") - for _, fn := range beforeMetricsCalledFns { - fn() - } promhttp.Handler().ServeHTTP(res, req) } diff --git a/pipline/upload_pipeline/pipeline.go b/pipline/upload_pipeline/pipeline.go index a2c46d02e804eb17137227bcffce4ffebac247fb..0d10ad0219bc81b83bf901b5098e0cf666073418 100644 --- a/pipline/upload_pipeline/pipeline.go +++ b/pipline/upload_pipeline/pipeline.go @@ -8,11 +8,11 @@ import ( "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/types" - "github.com/turt2live/matrix-media-repo/util/cleanup" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) func UploadMedia(ctx rcontext.RequestContext, origin string, mediaId string, r io.ReadCloser, contentType string, fileName string, userId string) (*types.Media, error) { - defer cleanup.DumpAndCloseStream(r) + defer stream_util.DumpAndCloseStream(r) // Step 1: Limit the stream's length r = limitStreamLength(ctx, r) @@ -63,4 +63,4 @@ func UploadMedia(ctx rcontext.RequestContext, origin string, mediaId string, r i // TODO return nil, errors.New("not yet implemented") -} \ No newline at end of file +} diff --git a/pipline/upload_pipeline/step_gen_media_id.go b/pipline/upload_pipeline/step_gen_media_id.go index a2ce11acb280c640074ab09ee912dec82f133631..9f09aa4b5bc696c124171a8a05535e0e04a6e0eb 100644 --- a/pipline/upload_pipeline/step_gen_media_id.go +++ b/pipline/upload_pipeline/step_gen_media_id.go @@ -2,13 +2,12 @@ package upload_pipeline import ( "errors" - "strconv" + "github.com/turt2live/matrix-media-repo/util/ids" "time" "github.com/patrickmn/go-cache" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/storage" - "github.com/turt2live/matrix-media-repo/util" ) var recentMediaIds = cache.New(30*time.Second, 60*time.Second) @@ -25,14 +24,7 @@ func generateMediaID(ctx rcontext.RequestContext, origin string) (string, error) return "", errors.New("failed to generate a media ID after 10 rounds") } - mediaId, err = util.GenerateRandomString(64) - if err != nil { - return "", err - } - mediaId, err = util.GetSha1OfString(mediaId + strconv.FormatInt(util.NowMillis(), 10)) - if err != nil { - return "", err - } + mediaId, err = ids.NewUniqueId() // Because we use the current time in the media ID, we don't need to worry about // collisions from the database. diff --git a/pipline/upload_pipeline/step_hash.go b/pipline/upload_pipeline/step_hash.go index 66072ee7ce7a5763508309e35e60479f4571e1f1..eedab08cb9a0206db24ac61b78c874fa9913a0d0 100644 --- a/pipline/upload_pipeline/step_hash.go +++ b/pipline/upload_pipeline/step_hash.go @@ -4,9 +4,9 @@ import ( "io" "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/util" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) func hashFile(ctx rcontext.RequestContext, r io.ReadCloser) (string, error) { - return util.GetSha256HashOfStream(r) + return stream_util.GetSha256HashOfStream(r) } diff --git a/storage/datastore/datastore.go b/storage/datastore/datastore.go index 26a9f35ec4d0db13b842d8d3b57b81dd267679a2..e03c3cf81f4c2151402892a359d23a44f1895b86 100644 --- a/storage/datastore/datastore.go +++ b/storage/datastore/datastore.go @@ -2,9 +2,10 @@ package datastore import ( "fmt" + "io" + "github.com/getsentry/sentry-go" "github.com/turt2live/matrix-media-repo/common" - "io" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -87,8 +88,6 @@ func GetUriForDatastore(dsConf config.DatastoreConfig) string { } else { return fmt.Sprintf("s3://%s/%s", endpoint, bucket) } - } else if dsConf.Type == "ipfs" { - return "ipfs://localhost" } else { sentry.CaptureException(errors.New("unknown datastore type: " + dsConf.Type)) logrus.Fatal("Unknown datastore type: ", dsConf.Type) diff --git a/storage/datastore/datastore_ref.go b/storage/datastore/datastore_ref.go index a4e45d2adaaa212627a053700f96761ad0b947e2..9d8e62dd2cb20e0c00d3e207c9632cc645676513 100644 --- a/storage/datastore/datastore_ref.go +++ b/storage/datastore/datastore_ref.go @@ -10,7 +10,6 @@ import ( config2 "github.com/turt2live/matrix-media-repo/common/config" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/storage/datastore/ds_file" - "github.com/turt2live/matrix-media-repo/storage/datastore/ds_ipfs" "github.com/turt2live/matrix-media-repo/storage/datastore/ds_s3" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" @@ -47,8 +46,6 @@ func (d *DatastoreRef) UploadFile(file io.ReadCloser, expectedLength int64, ctx return nil, err } return s3.UploadFile(file, expectedLength, ctx) - } else if d.Type == "ipfs" { - return ds_ipfs.UploadFile(file, ctx) } else { return nil, errors.New("unknown datastore type") } @@ -63,10 +60,6 @@ func (d *DatastoreRef) DeleteObject(location string) error { return err } return s3.DeleteObject(location) - } else if d.Type == "ipfs" { - // TODO: Support deleting from IPFS - will need a "delete reason" to avoid deleting duplicates - logrus.Warn("Unsupported operation: deleting from IPFS datastore") - return nil } else { return errors.New("unknown datastore type") } @@ -81,8 +74,6 @@ func (d *DatastoreRef) DownloadFile(location string) (io.ReadCloser, error) { return nil, err } return s3.DownloadObject(location) - } else if d.Type == "ipfs" { - return ds_ipfs.DownloadFile(location) } else { return nil, errors.New("unknown datastore type") } @@ -101,10 +92,6 @@ func (d *DatastoreRef) ObjectExists(location string) bool { return false } return s3.ObjectExists(location) - } else if d.Type == "ipfs" { - // TODO: Support checking file existence in IPFS - logrus.Warn("Unsupported operation: existence in IPFS datastore") - return false } else { panic("unknown datastore type") } @@ -120,10 +107,6 @@ func (d *DatastoreRef) OverwriteObject(location string, stream io.ReadCloser, ct return err } return s3.OverwriteObject(location, stream) - } else if d.Type == "ipfs" { - // TODO: Support overwriting in IPFS - logrus.Warn("Unsupported operation: overwriting file in IPFS datastore") - return errors.New("unsupported operation") } else { return errors.New("unknown datastore type") } diff --git a/storage/datastore/ds_file/file_store.go b/storage/datastore/ds_file/file_store.go index 8655bdf64c6a6137a5b5d52702d78a248dc97e0b..74a5df07c20f2c79524050e91195ca2d543612dd 100644 --- a/storage/datastore/ds_file/file_store.go +++ b/storage/datastore/ds_file/file_store.go @@ -7,14 +7,16 @@ import ( "os" "path" + "github.com/turt2live/matrix-media-repo/util/ids" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/types" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) func PersistFile(basePath string, file io.ReadCloser, ctx rcontext.RequestContext) (*types.ObjectInfo, error) { - defer cleanup.DumpAndCloseStream(file) + defer stream_util.DumpAndCloseStream(file) exists := true var primaryContainer string @@ -24,7 +26,7 @@ func PersistFile(basePath string, file io.ReadCloser, ctx rcontext.RequestContex var targetFile string attempts := 0 for exists { - fileId, err := util.GenerateRandomString(64) + fileId, err := ids.NewUniqueId() if err != nil { return nil, err } @@ -69,13 +71,13 @@ func PersistFile(basePath string, file io.ReadCloser, ctx rcontext.RequestContex } func PersistFileAtLocation(targetFile string, file io.ReadCloser, ctx rcontext.RequestContext) (int64, string, error) { - defer cleanup.DumpAndCloseStream(file) + defer stream_util.DumpAndCloseStream(file) f, err := os.OpenFile(targetFile, os.O_WRONLY|os.O_CREATE, 0644) if err != nil { return 0, "", err } - defer cleanup.DumpAndCloseStream(f) + defer stream_util.DumpAndCloseStream(f) rfile, wfile := io.Pipe() tr := io.TeeReader(file, wfile) @@ -91,7 +93,7 @@ func PersistFileAtLocation(targetFile string, file io.ReadCloser, ctx rcontext.R go func() { defer wfile.Close() ctx.Log.Info("Calculating hash of stream...") - hash, hashErr = util.GetSha256HashOfStream(ioutil.NopCloser(tr)) + hash, hashErr = stream_util.GetSha256HashOfStream(ioutil.NopCloser(tr)) ctx.Log.Info("Hash of file is ", hash) done <- true }() diff --git a/storage/datastore/ds_ipfs/ipfs_store.go b/storage/datastore/ds_ipfs/ipfs_store.go deleted file mode 100644 index 9f26d029e5236bd75a76853e2fb762bbeaeb3e4e..0000000000000000000000000000000000000000 --- a/storage/datastore/ds_ipfs/ipfs_store.go +++ /dev/null @@ -1,73 +0,0 @@ -package ds_ipfs - -import ( - "bytes" - "io" - "io/ioutil" - - "github.com/turt2live/matrix-media-repo/common/rcontext" - "github.com/turt2live/matrix-media-repo/ipfs_proxy" - "github.com/turt2live/matrix-media-repo/types" - "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" -) - -func UploadFile(file io.ReadCloser, ctx rcontext.RequestContext) (*types.ObjectInfo, error) { - defer cleanup.DumpAndCloseStream(file) - - b, err := ioutil.ReadAll(file) - if err != nil { - return nil, err - } - - done := make(chan bool) - defer close(done) - - var cid string - var hash string - var hashErr error - var writeErr error - - go func() { - ctx.Log.Info("Writing file...") - cid, writeErr = ipfs_proxy.PutObject(bytes.NewBuffer(b), ctx) - ctx.Log.Info("Wrote file to IPFS") - done <- true - }() - - go func() { - ctx.Log.Info("Calculating hash of stream...") - hash, hashErr = util.GetSha256HashOfStream(ioutil.NopCloser(bytes.NewBuffer(b))) - ctx.Log.Info("Hash of file is ", hash) - done <- true - }() - - for c := 0; c < 2; c++ { - <-done - } - - if hashErr != nil { - return nil, hashErr - } - if writeErr != nil { - return nil, writeErr - } - - return &types.ObjectInfo{ - Location: "ipfs/" + cid, - Sha256Hash: hash, - SizeBytes: int64(len(b)), - }, nil -} - -func DownloadFile(location string) (io.ReadCloser, error) { - cid := location[len("ipfs/"):] - ctx := rcontext.Initial() - - obj, err := ipfs_proxy.GetObject(cid, ctx) - if err != nil { - return nil, err - } - - return obj.Data, nil -} diff --git a/storage/datastore/ds_s3/s3_store.go b/storage/datastore/ds_s3/s3_store.go index 05e06b77a1f7d6a8558b550f2a80943854b47cbe..511374ab83269eae9a981ea34fd676c36a1571b8 100644 --- a/storage/datastore/ds_s3/s3_store.go +++ b/storage/datastore/ds_s3/s3_store.go @@ -8,6 +8,9 @@ import ( "strconv" "strings" + "github.com/turt2live/matrix-media-repo/util/ids" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/minio/minio-go/v6" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" @@ -16,8 +19,6 @@ import ( "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/metrics" "github.com/turt2live/matrix-media-repo/types" - "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) var stores = make(map[string]*s3Datastore) @@ -130,9 +131,9 @@ func (s *s3Datastore) EnsureTempPathExists() error { } func (s *s3Datastore) UploadFile(file io.ReadCloser, expectedLength int64, ctx rcontext.RequestContext) (*types.ObjectInfo, error) { - defer cleanup.DumpAndCloseStream(file) + defer stream_util.DumpAndCloseStream(file) - objectName, err := util.GenerateRandomString(512) + objectName, err := ids.NewUniqueId() if err != nil { return nil, err } @@ -153,7 +154,7 @@ func (s *s3Datastore) UploadFile(file io.ReadCloser, expectedLength int64, ctx r go func() { defer ws3.Close() ctx.Log.Info("Calculating hash of stream...") - hash, hashErr = util.GetSha256HashOfStream(ioutil.NopCloser(tr)) + hash, hashErr = stream_util.GetSha256HashOfStream(ioutil.NopCloser(tr)) ctx.Log.Info("Hash of file is ", hash) done <- true }() @@ -171,14 +172,14 @@ func (s *s3Datastore) UploadFile(file io.ReadCloser, expectedLength int64, ctx r } defer os.Remove(f.Name()) expectedLength, uploadErr = io.Copy(f, rs3) - cleanup.DumpAndCloseStream(f) + stream_util.DumpAndCloseStream(f) f, uploadErr = os.Open(f.Name()) if uploadErr != nil { done <- true return } rs3 = f - defer cleanup.DumpAndCloseStream(f) + defer stream_util.DumpAndCloseStream(f) } else { ctx.Log.Warn("Uploading content of unknown length to s3 - this could result in high memory usage") expectedLength = -1 @@ -235,7 +236,7 @@ func (s *s3Datastore) ObjectExists(location string) bool { } func (s *s3Datastore) OverwriteObject(location string, stream io.ReadCloser) error { - defer cleanup.DumpAndCloseStream(stream) + defer stream_util.DumpAndCloseStream(stream) metrics.S3Operations.With(prometheus.Labels{"operation": "PutObject"}).Inc() _, err := s.client.PutObject(s.bucket, location, stream, -1, minio.PutObjectOptions{StorageClass: s.storageClass}) return err diff --git a/storage/ds_utils.go b/storage/ds_utils.go index 6c8a553fea6d488c72d715be9e7e49eb8380f2e7..d925348f5ec754df4864c6f7ce89b9fc5223ac5d 100644 --- a/storage/ds_utils.go +++ b/storage/ds_utils.go @@ -2,19 +2,19 @@ package storage import ( "database/sql" + "github.com/turt2live/matrix-media-repo/util/ids" "github.com/sirupsen/logrus" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/storage/stores" "github.com/turt2live/matrix-media-repo/types" - "github.com/turt2live/matrix-media-repo/util" ) func GetOrCreateDatastoreOfType(ctx rcontext.RequestContext, dsType string, dsUri string) (*types.Datastore, error) { mediaService := GetDatabase().GetMediaStore(ctx) datastore, err := mediaService.GetDatastoreByUri(dsUri) if err != nil && err == sql.ErrNoRows { - id, err2 := util.GenerateRandomString(32) + id, err2 := ids.NewUniqueId() if err2 != nil { ctx.Log.Error("Error generating datastore ID for URI ", dsUri, ": ", err) return nil, err2 @@ -36,7 +36,7 @@ func GetOrCreateDatastoreOfType(ctx rcontext.RequestContext, dsType string, dsUr func getOrCreateDatastoreWithMediaService(mediaService *stores.MediaStore, basePath string) (*types.Datastore, error) { datastore, err := mediaService.GetDatastoreByUri(basePath) if err != nil && err == sql.ErrNoRows { - id, err2 := util.GenerateRandomString(32) + id, err2 := ids.NewUniqueId() if err2 != nil { logrus.Error("Error generating datastore ID for base path ", basePath, ": ", err) return nil, err2 diff --git a/thumbnailing/i/jpegxl.go b/thumbnailing/i/jpegxl.go index 7c46f0a3e624711a990016c21977cc9933a2eea8..9294cc58f82cda090e9a2a2b2da10327a1f369fd 100644 --- a/thumbnailing/i/jpegxl.go +++ b/thumbnailing/i/jpegxl.go @@ -7,10 +7,11 @@ import ( "os/exec" "path" + "github.com/turt2live/matrix-media-repo/util/ids" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/thumbnailing/m" - "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) type jpegxlGenerator struct { @@ -33,7 +34,7 @@ func (d jpegxlGenerator) GetOriginDimensions(b []byte, contentType string, ctx r } func (d jpegxlGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) { - key, err := util.GenerateRandomString(16) + key, err := ids.NewUniqueId() if err != nil { return nil, errors.New("jpegxl: error generating temp key: " + err.Error()) } @@ -49,7 +50,7 @@ func (d jpegxlGenerator) GenerateThumbnail(b []byte, contentType string, width i return nil, errors.New("jpegxl: error writing temp jpegxl file: " + err.Error()) } _, _ = f.Write(b) - cleanup.DumpAndCloseStream(f) + stream_util.DumpAndCloseStream(f) err = exec.Command("convert", tempFile1, tempFile2).Run() if err != nil { diff --git a/thumbnailing/i/mp4.go b/thumbnailing/i/mp4.go index 689db9202e8c758eb678d17e38792cf7c032380c..e6cceb521dc16be0f75f61c420a95cefa8b1896c 100644 --- a/thumbnailing/i/mp4.go +++ b/thumbnailing/i/mp4.go @@ -7,10 +7,12 @@ import ( "os/exec" "path" + "github.com/turt2live/matrix-media-repo/util/ids" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/thumbnailing/m" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) type mp4Generator struct { @@ -33,7 +35,7 @@ func (d mp4Generator) GetOriginDimensions(b []byte, contentType string, ctx rcon } func (d mp4Generator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) { - key, err := util.GenerateRandomString(16) + key, err := ids.NewUniqueId() if err != nil { return nil, errors.New("mp4: error generating temp key: " + err.Error()) } @@ -49,7 +51,7 @@ func (d mp4Generator) GenerateThumbnail(b []byte, contentType string, width int, return nil, errors.New("mp4: error writing temp video file: " + err.Error()) } _, _ = f.Write(b) - cleanup.DumpAndCloseStream(f) + stream_util.DumpAndCloseStream(f) err = exec.Command("ffmpeg", "-i", tempFile1, "-vf", "select=eq(n\\,0)", tempFile2).Run() if err != nil { diff --git a/thumbnailing/i/svg.go b/thumbnailing/i/svg.go index e7f8cafcf3177291127447accea52d180ea2a024..98b622ac39cc381b9fbda68c6d74104f275e8c96 100644 --- a/thumbnailing/i/svg.go +++ b/thumbnailing/i/svg.go @@ -7,10 +7,11 @@ import ( "os/exec" "path" + "github.com/turt2live/matrix-media-repo/util/ids" + "github.com/turt2live/matrix-media-repo/util/stream_util" + "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/thumbnailing/m" - "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) type svgGenerator struct { @@ -33,7 +34,7 @@ func (d svgGenerator) GetOriginDimensions(b []byte, contentType string, ctx rcon } func (d svgGenerator) GenerateThumbnail(b []byte, contentType string, width int, height int, method string, animated bool, ctx rcontext.RequestContext) (*m.Thumbnail, error) { - key, err := util.GenerateRandomString(16) + key, err := ids.NewUniqueId() if err != nil { return nil, errors.New("svg: error generating temp key: " + err.Error()) } @@ -49,7 +50,7 @@ func (d svgGenerator) GenerateThumbnail(b []byte, contentType string, width int, return nil, errors.New("svg: error writing temp svg file: " + err.Error()) } _, _ = f.Write(b) - cleanup.DumpAndCloseStream(f) + stream_util.DumpAndCloseStream(f) err = exec.Command("convert", tempFile1, tempFile2).Run() if err != nil { diff --git a/thumbnailing/thumbnail.go b/thumbnailing/thumbnail.go index 2d124592a8b9945a4a2db38fb894adf5163f0525..0897a209a4cffa85b3cd29357f03e6441e64698d 100644 --- a/thumbnailing/thumbnail.go +++ b/thumbnailing/thumbnail.go @@ -7,12 +7,12 @@ import ( "reflect" "github.com/turt2live/matrix-media-repo/common" + "github.com/turt2live/matrix-media-repo/util/stream_util" "github.com/turt2live/matrix-media-repo/common/rcontext" "github.com/turt2live/matrix-media-repo/thumbnailing/i" "github.com/turt2live/matrix-media-repo/thumbnailing/m" "github.com/turt2live/matrix-media-repo/util" - "github.com/turt2live/matrix-media-repo/util/cleanup" ) var ErrUnsupported = errors.New("unsupported thumbnail type") @@ -30,7 +30,7 @@ func GenerateThumbnail(imgStream io.ReadCloser, contentType string, width int, h return nil, ErrUnsupported } - defer cleanup.DumpAndCloseStream(imgStream) + defer stream_util.DumpAndCloseStream(imgStream) b, err := ioutil.ReadAll(imgStream) if err != nil { return nil, err @@ -57,7 +57,7 @@ func GenerateThumbnail(imgStream io.ReadCloser, contentType string, width int, h } func GetGenerator(imgStream io.ReadCloser, contentType string, animated bool) (i.Generator, error) { - defer cleanup.DumpAndCloseStream(imgStream) + defer stream_util.DumpAndCloseStream(imgStream) b, err := ioutil.ReadAll(imgStream) if err != nil { return nil, err diff --git a/util/cleanup/stream_cleanup.go b/util/cleanup/stream_cleanup.go deleted file mode 100644 index 52056716c3e515e34c8830fd23584ac80d7a0123..0000000000000000000000000000000000000000 --- a/util/cleanup/stream_cleanup.go +++ /dev/null @@ -1,14 +0,0 @@ -package cleanup - -import ( - "io" - "io/ioutil" -) - -func DumpAndCloseStream(r io.ReadCloser) { - if r == nil { - return // nothing to dump or close - } - _, _ = io.Copy(ioutil.Discard, r) - _ = r.Close() -} diff --git a/util/download_tracker/tracker.go b/util/download_tracker/tracker.go deleted file mode 100644 index bf933df66e0c90079d283c29370fbd2bd7d8de82..0000000000000000000000000000000000000000 --- a/util/download_tracker/tracker.go +++ /dev/null @@ -1,121 +0,0 @@ -package download_tracker - -import ( - "container/list" - "time" - - "github.com/patrickmn/go-cache" - "github.com/turt2live/matrix-media-repo/util" -) - -/* - * The download tracker works by keeping a limited number of buckets for each media record - * in an expiring cache. The number of buckets is the equal to the number of minutes to track - * downloads for (max age). The entire download history expires after the max age so long - * as it is not added to. - * - * The underlying data structure is a linked list of buckets (which are just a timestamp and - * number of downloads). A linked list was chosen for it's capability to easily append and - * remove items without having to do array slicing. Buckets were chosen to limit the number - * of entries in the list because the total downloads are calculated through iteration. If - * each calculation had to iterate over thousands of items, the execution would be slow. A - * smaller number, like 30, is a lot more manageable. - */ - -type DownloadTracker struct { - cache *cache.Cache - maxAge int64 -} - -type mediaRecord struct { - buckets *list.List - downloads int -} - -type bucket struct { - ts int64 - downloads int -} - -func New(maxAgeMinutes int) *DownloadTracker { - maxAge := time.Duration(maxAgeMinutes) * time.Minute - return &DownloadTracker{ - cache: cache.New(maxAge, maxAge*2), - maxAge: int64(maxAgeMinutes), - } -} - -func (d *DownloadTracker) Reset() { - d.cache.Flush() -} - -func (d *DownloadTracker) NumDownloads(recordId string) int { - item, found := d.cache.Get(recordId) - if !found { - return 0 - } - - return d.recountDownloads(item.(*mediaRecord), recordId) -} - -func (d *DownloadTracker) Increment(recordId string) int { - item, found := d.cache.Get(recordId) - var record *mediaRecord - if !found { - record = &mediaRecord{buckets: list.New()} - } else { - record = item.(*mediaRecord) - } - - bucketTs := util.NowMillis() / 60000 // minutes - - if record.buckets.Len() <= 0 { - // First bucket - record.buckets.PushFront(&bucket{ - ts: bucketTs, - downloads: 1, - }) - } else { - firstRecord := record.buckets.Front().Value.(*bucket) - if firstRecord.ts != bucketTs { - record.buckets.PushFront(&bucket{ - ts: bucketTs, - downloads: 1, - }) - } else { - firstRecord.downloads++ - } - } - - return d.recountDownloads(record, recordId) -} - -func (d *DownloadTracker) recountDownloads(record *mediaRecord, recordId string) int { - currentBucketTs := util.NowMillis() / 60000 // minutes - changed := false - - // Trim off anything that is too old - for e := record.buckets.Back(); e != nil; e = record.buckets.Back() { - b := e.Value.(*bucket) - if (currentBucketTs - b.ts) > d.maxAge { - changed = true - record.buckets.Remove(e) - } else { - break // count is still relevant - } - } - - // Count the number of downloads - downloads := 0 - for e := record.buckets.Front(); e != nil; e = e.Next() { - b := e.Value.(*bucket) - downloads += b.downloads - } - - if changed || downloads != record.downloads { - record.downloads = downloads - d.cache.Set(recordId, record, cache.DefaultExpiration) - } - - return downloads -} diff --git a/util/files.go b/util/files.go index 53f8896ded68a198e58ccc9dba437f967508c350..178ae1d8815cd4be638504bc2640705bf043c360 100644 --- a/util/files.go +++ b/util/files.go @@ -4,7 +4,7 @@ import ( "os" "path" - "github.com/turt2live/matrix-media-repo/util/cleanup" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) func FileExists(path string) (bool, error) { @@ -33,7 +33,7 @@ func GetFileHash(filePath string) (string, error) { if err != nil { return "", err } - defer cleanup.DumpAndCloseStream(f) + defer stream_util.DumpAndCloseStream(f) - return GetSha256HashOfStream(f) + return stream_util.GetSha256HashOfStream(f) } diff --git a/util/ids/unique.go b/util/ids/unique.go new file mode 100644 index 0000000000000000000000000000000000000000..2baa7fec730375d0fb2c5de7966c716b09479f22 --- /dev/null +++ b/util/ids/unique.go @@ -0,0 +1,20 @@ +package ids + +import ( + "github.com/turt2live/matrix-media-repo/cluster" + "github.com/turt2live/matrix-media-repo/common/config" + "github.com/turt2live/matrix-media-repo/util" + "strconv" +) + +func NewUniqueId() (string, error) { + if config.Get().Cluster.IDGenerator.Secret != "" { + return cluster.GetId() + } + + b, err := util.GenerateRandomBytes(64) + if err != nil { + return "", err + } + return util.GetSha1OfString(string(b) + strconv.FormatInt(util.NowMillis(), 10)) +} diff --git a/util/stream_util/streams.go b/util/stream_util/streams.go new file mode 100644 index 0000000000000000000000000000000000000000..0717f8bbd6b110c4ed12d050fa3a972b4d3f9d5f --- /dev/null +++ b/util/stream_util/streams.go @@ -0,0 +1,124 @@ +package stream_util + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "io" + "io/ioutil" + "math" + + "github.com/turt2live/matrix-media-repo/util/util_byte_seeker" +) + +func BufferToStream(buf *bytes.Buffer) io.ReadCloser { + newBuf := bytes.NewReader(buf.Bytes()) + return ioutil.NopCloser(newBuf) +} + +func BytesToStream(b []byte) io.ReadCloser { + return ioutil.NopCloser(bytes.NewBuffer(b)) +} + +func CloneReader(input io.ReadCloser, numReaders int) []io.ReadCloser { + readers := make([]io.ReadCloser, 0) + writers := make([]io.WriteCloser, 0) + + for i := 0; i < numReaders; i++ { + r, w := io.Pipe() + readers = append(readers, r) + writers = append(writers, w) + } + + go func() { + plainWriters := make([]io.Writer, 0) + for _, w := range writers { + defer w.Close() + plainWriters = append(plainWriters, w) + } + + mw := io.MultiWriter(plainWriters...) + io.Copy(mw, input) + }() + + return readers +} + +func GetSha256HashOfStream(r io.ReadCloser) (string, error) { + defer DumpAndCloseStream(r) + + hasher := sha256.New() + + if _, err := io.Copy(hasher, r); err != nil { + return "", err + } + + return hex.EncodeToString(hasher.Sum(nil)), nil +} + +func ClonedBufReader(buf bytes.Buffer) util_byte_seeker.ByteSeeker { + return util_byte_seeker.NewByteSeeker(buf.Bytes()) +} + +func ForceDiscard(r io.Reader, nBytes int64) error { + if nBytes == 0 { + return nil // weird call, but ok + } + + buf := make([]byte, 128) + + if nBytes < 0 { + for true { + _, err := r.Read(buf) + if err == io.EOF { + break + } else if err != nil { + return err + } + } + return nil + } + + read := int64(0) + for (nBytes - read) > 0 { + toRead := int(math.Min(float64(len(buf)), float64(nBytes-read))) + if toRead != len(buf) { + buf = make([]byte, toRead) + } + actuallyRead, err := r.Read(buf) + if err != nil { + return err + } + read += int64(actuallyRead) + if (nBytes - read) < 0 { + return errors.New(fmt.Sprintf("over-discarded from stream by %d bytes", nBytes-read)) + } + } + + return nil +} + +func ManualSeekStream(r io.Reader, bytesStart int64, bytesToRead int64) (io.Reader, error) { + if sr, ok := r.(io.ReadSeeker); ok { + _, err := sr.Seek(bytesStart, io.SeekStart) + if err != nil { + return nil, err + } + } else { + err := ForceDiscard(r, bytesStart) + if err != nil { + return nil, err + } + } + return io.LimitReader(r, bytesToRead), nil +} + +func DumpAndCloseStream(r io.ReadCloser) { + if r == nil { + return // nothing to dump or close + } + _ = ForceDiscard(r, -1) + _ = r.Close() +} diff --git a/util/streams.go b/util/streams.go deleted file mode 100644 index 9cafc8ba5d38db9f14893367246149513db74347..0000000000000000000000000000000000000000 --- a/util/streams.go +++ /dev/null @@ -1,61 +0,0 @@ -package util - -import ( - "bytes" - "crypto/sha256" - "encoding/hex" - "io" - "io/ioutil" - - "github.com/turt2live/matrix-media-repo/util/cleanup" - "github.com/turt2live/matrix-media-repo/util/util_byte_seeker" -) - -func BufferToStream(buf *bytes.Buffer) io.ReadCloser { - newBuf := bytes.NewReader(buf.Bytes()) - return ioutil.NopCloser(newBuf) -} - -func BytesToStream(b []byte) io.ReadCloser { - return ioutil.NopCloser(bytes.NewBuffer(b)) -} - -func CloneReader(input io.ReadCloser, numReaders int) []io.ReadCloser { - readers := make([]io.ReadCloser, 0) - writers := make([]io.WriteCloser, 0) - - for i := 0; i < numReaders; i++ { - r, w := io.Pipe() - readers = append(readers, r) - writers = append(writers, w) - } - - go func() { - plainWriters := make([]io.Writer, 0) - for _, w := range writers { - defer w.Close() - plainWriters = append(plainWriters, w) - } - - mw := io.MultiWriter(plainWriters...) - io.Copy(mw, input) - }() - - return readers -} - -func GetSha256HashOfStream(r io.ReadCloser) (string, error) { - defer cleanup.DumpAndCloseStream(r) - - hasher := sha256.New() - - if _, err := io.Copy(hasher, r); err != nil { - return "", err - } - - return hex.EncodeToString(hasher.Sum(nil)), nil -} - -func ClonedBufReader(buf bytes.Buffer) util_byte_seeker.ByteSeeker { - return util_byte_seeker.NewByteSeeker(buf.Bytes()) -} \ No newline at end of file diff --git a/util/util_exif/exif.go b/util/util_exif/exif.go index 4226576cd0c9ed0a7c0d748923196ea9df225613..47cdb2842952f283535b61d90f3739cfef661377 100644 --- a/util/util_exif/exif.go +++ b/util/util_exif/exif.go @@ -2,10 +2,11 @@ package util_exif import ( "fmt" + "io" + "github.com/dsoprea/go-exif/v3" "github.com/pkg/errors" - "github.com/turt2live/matrix-media-repo/util/cleanup" - "io" + "github.com/turt2live/matrix-media-repo/util/stream_util" ) type ExifOrientation struct { @@ -15,7 +16,7 @@ type ExifOrientation struct { } func GetExifOrientation(img io.ReadCloser) (*ExifOrientation, error) { - defer cleanup.DumpAndCloseStream(img) + defer stream_util.DumpAndCloseStream(img) rawExif, err := exif.SearchAndExtractExifWithReader(img) if err != nil {