mirror of
https://github.com/mattermost/mattermost.git
synced 2026-08-29 02:28:16 +08:00
@@ -215,7 +215,8 @@ func NewChannels(s *Server) (*Channels, error) {
|
||||
decoderConcurrency = runtime.NumCPU()
|
||||
}
|
||||
ch.imgDecoder, imgErr = imaging.NewDecoder(imaging.DecoderOptions{
|
||||
ConcurrencyLevel: decoderConcurrency,
|
||||
ConcurrencyLevel: decoderConcurrency,
|
||||
MaxDecodedResolution: *ch.cfgSvc.Config().FileSettings.MaxImageResolution,
|
||||
})
|
||||
if imgErr != nil {
|
||||
return nil, errors.Wrap(imgErr, "failed to create image decoder")
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
@@ -23,6 +24,13 @@ type DecoderOptions struct {
|
||||
// The level of concurrency for the decoder. This defines a limit on the
|
||||
// number of concurrently running encoding goroutines.
|
||||
ConcurrencyLevel int
|
||||
|
||||
// MaxDecodedResolution, when greater than zero, is the maximum number of
|
||||
// pixels (width*height) an image may declare before it is decoded. Images
|
||||
// exceeding this limit are rejected up front. This is a defense-in-depth
|
||||
// guard against decompression bombs that bounds server-side memory
|
||||
// allocation regardless of the underlying codec's behavior.
|
||||
MaxDecodedResolution int64
|
||||
}
|
||||
|
||||
func (o *DecoderOptions) validate() error {
|
||||
@@ -52,8 +60,76 @@ func NewDecoder(opts DecoderOptions) (*Decoder, error) {
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
// enforceResolutionLimit inspects the image header and rejects images whose
|
||||
// declared resolution exceeds the configured MaxDecodedResolution before any
|
||||
// pixel data is decoded. It returns the reader to use for the subsequent full
|
||||
// decode: seekable readers are rewound to their original position, while
|
||||
// non-seekable readers are buffered so the cap is enforced for every input.
|
||||
func (d *Decoder) enforceResolutionLimit(rd io.Reader) (io.Reader, error) {
|
||||
if d.opts.MaxDecodedResolution <= 0 {
|
||||
return rd, nil
|
||||
}
|
||||
|
||||
if seeker, ok := rd.(io.ReadSeeker); ok {
|
||||
// Preserve the caller's position so an image decoded from a non-zero
|
||||
// offset still lines up for the full decode.
|
||||
start, err := seeker.Seek(0, io.SeekCurrent)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("imaging: failed to read image position: %w", err)
|
||||
}
|
||||
cfg, _, cfgErr := image.DecodeConfig(seeker)
|
||||
if _, err := seeker.Seek(start, io.SeekStart); err != nil {
|
||||
return nil, fmt.Errorf("imaging: failed to seek after reading image config: %w", err)
|
||||
}
|
||||
if err := d.checkConfigResolution(cfg, cfgErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rd, nil
|
||||
}
|
||||
|
||||
// Non-seekable reader: buffer the input so the resolution cap can still be
|
||||
// enforced and the data can be decoded afterwards.
|
||||
data, err := io.ReadAll(rd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("imaging: failed to read image data: %w", err)
|
||||
}
|
||||
cfg, _, cfgErr := image.DecodeConfig(bytes.NewReader(data))
|
||||
if err := d.checkConfigResolution(cfg, cfgErr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes.NewReader(data), nil
|
||||
}
|
||||
|
||||
// checkConfigResolution rejects a decoded image config whose resolution exceeds
|
||||
// the configured cap. A config-decode error is ignored so the subsequent full
|
||||
// decode can surface a meaningful error for malformed input.
|
||||
func (d *Decoder) checkConfigResolution(cfg image.Config, cfgErr error) error {
|
||||
if cfgErr != nil {
|
||||
return nil
|
||||
}
|
||||
if exceedsResolution(int64(cfg.Width), int64(cfg.Height), d.opts.MaxDecodedResolution) {
|
||||
return fmt.Errorf("imaging: image resolution %dx%d exceeds the maximum allowed %d pixels", cfg.Width, cfg.Height, d.opts.MaxDecodedResolution)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// exceedsResolution reports whether width*height exceeds maxRes. It divides
|
||||
// instead of multiplying so it can't overflow int64 for very large declared
|
||||
// dimensions.
|
||||
func exceedsResolution(width, height, maxRes int64) bool {
|
||||
if width <= 0 || height <= 0 {
|
||||
return false
|
||||
}
|
||||
return width > maxRes/height
|
||||
}
|
||||
|
||||
// Decode decodes the given encoded data and returns the decoded image.
|
||||
func (d *Decoder) Decode(rd io.Reader) (img image.Image, format string, err error) {
|
||||
rd, err = d.enforceResolutionLimit(rd)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if d.opts.ConcurrencyLevel != 0 {
|
||||
d.sem <- struct{}{}
|
||||
defer func() { <-d.sem }()
|
||||
@@ -71,6 +147,11 @@ func (d *Decoder) Decode(rd io.Reader) (img image.Image, format string, err erro
|
||||
// must be called when access to the raw image is not needed anymore.
|
||||
// This sets the raw image data pointer to nil in an attempt to help the GC to re-use the underlying data as soon as possible.
|
||||
func (d *Decoder) DecodeMemBounded(rd io.Reader) (img image.Image, format string, releaseFunc func(), err error) {
|
||||
rd, err = d.enforceResolutionLimit(rd)
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
|
||||
if d.opts.ConcurrencyLevel != 0 {
|
||||
d.sem <- struct{}{}
|
||||
defer func() {
|
||||
|
||||
@@ -5,6 +5,9 @@ package imaging
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/png"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -256,3 +259,87 @@ func TestDecoderDecodeMemBounded(t *testing.T) {
|
||||
require.Empty(t, d.sem)
|
||||
})
|
||||
}
|
||||
|
||||
// TestDecoderMaxDecodedResolution verifies the defense-in-depth cap: the shared
|
||||
// decoder refuses to decode any image whose declared resolution exceeds the
|
||||
// configured limit, regardless of the underlying codec, before allocating
|
||||
// pixel data.
|
||||
func TestDecoderMaxDecodedResolution(t *testing.T) {
|
||||
makePNG := func(w, h int) []byte {
|
||||
var buf bytes.Buffer
|
||||
require.NoError(t, png.Encode(&buf, image.NewRGBA(image.Rect(0, 0, w, h))))
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
d, err := NewDecoder(DecoderOptions{MaxDecodedResolution: 100})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("Decode rejects image exceeding the cap", func(t *testing.T) {
|
||||
img, format, decErr := d.Decode(bytes.NewReader(makePNG(50, 50))) // 2500px > 100
|
||||
require.Error(t, decErr)
|
||||
require.ErrorContains(t, decErr, "exceeds the maximum allowed")
|
||||
require.Nil(t, img)
|
||||
require.Empty(t, format)
|
||||
})
|
||||
|
||||
t.Run("Decode allows image within the cap", func(t *testing.T) {
|
||||
img, format, decErr := d.Decode(bytes.NewReader(makePNG(5, 5))) // 25px <= 100
|
||||
require.NoError(t, decErr)
|
||||
require.NotNil(t, img)
|
||||
require.Equal(t, "png", format)
|
||||
})
|
||||
|
||||
t.Run("DecodeMemBounded rejects image exceeding the cap", func(t *testing.T) {
|
||||
img, format, release, decErr := d.DecodeMemBounded(bytes.NewReader(makePNG(50, 50)))
|
||||
require.Error(t, decErr)
|
||||
require.ErrorContains(t, decErr, "exceeds the maximum allowed")
|
||||
require.Nil(t, img)
|
||||
require.Empty(t, format)
|
||||
require.Nil(t, release)
|
||||
})
|
||||
|
||||
t.Run("cap disabled by default", func(t *testing.T) {
|
||||
dd, ddErr := NewDecoder(DecoderOptions{})
|
||||
require.NoError(t, ddErr)
|
||||
img, _, decErr := dd.Decode(bytes.NewReader(makePNG(50, 50)))
|
||||
require.NoError(t, decErr)
|
||||
require.NotNil(t, img)
|
||||
})
|
||||
|
||||
// A non-seekable reader must still be subject to the cap; the decoder
|
||||
// buffers it internally rather than silently bypassing the check.
|
||||
t.Run("cap enforced on non-seekable reader", func(t *testing.T) {
|
||||
// io.MultiReader is not an io.ReadSeeker.
|
||||
img, format, decErr := d.Decode(io.MultiReader(bytes.NewReader(makePNG(50, 50))))
|
||||
require.Error(t, decErr)
|
||||
require.ErrorContains(t, decErr, "exceeds the maximum allowed")
|
||||
require.Nil(t, img)
|
||||
require.Empty(t, format)
|
||||
})
|
||||
|
||||
t.Run("non-seekable reader within cap decodes from buffer", func(t *testing.T) {
|
||||
img, format, decErr := d.Decode(io.MultiReader(bytes.NewReader(makePNG(5, 5))))
|
||||
require.NoError(t, decErr)
|
||||
require.NotNil(t, img)
|
||||
require.Equal(t, "png", format)
|
||||
})
|
||||
}
|
||||
|
||||
// TestExceedsResolution verifies the resolution comparison rejects over-limit
|
||||
// images (including dimensions large enough to overflow a naive int64
|
||||
// multiplication) without wrapping around.
|
||||
func TestExceedsResolution(t *testing.T) {
|
||||
const maxRes = int64(7680 * 4320) // default 8K cap, ~33 MPx
|
||||
|
||||
require.False(t, exceedsResolution(100, 100, maxRes))
|
||||
require.False(t, exceedsResolution(7680, 4320, maxRes)) // exactly at the cap
|
||||
require.True(t, exceedsResolution(10000, 10000, maxRes))
|
||||
|
||||
// width*height here (2^80) overflows int64; the division-based check must
|
||||
// still reject it rather than wrap to a small/negative value.
|
||||
require.True(t, exceedsResolution(1<<40, 1<<40, maxRes))
|
||||
|
||||
// Non-positive dimensions are treated as not exceeding the cap.
|
||||
require.False(t, exceedsResolution(0, 100, maxRes))
|
||||
require.False(t, exceedsResolution(100, 0, maxRes))
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
@@ -2043,8 +2042,10 @@ func (a *App) SetTeamIconFromMultiPartFile(rctx request.CTX, teamID string, file
|
||||
}
|
||||
|
||||
func (a *App) SetTeamIconFromFile(rctx request.CTX, team *model.Team, file io.ReadSeeker) *model.AppError {
|
||||
// Decode image into Image object
|
||||
img, format, err := image.Decode(file)
|
||||
// Decode image into Image object using the shared decoder so team icons
|
||||
// are subject to the same concurrency and resolution safeguards as other
|
||||
// user-uploaded images.
|
||||
img, format, err := a.ch.imgDecoder.Decode(file)
|
||||
if err != nil {
|
||||
return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.decode.app_error", nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
|
||||
+9
-9
@@ -74,13 +74,13 @@ require (
|
||||
github.com/wiggin77/merror v1.0.5
|
||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c
|
||||
github.com/yuin/goldmark v1.8.2
|
||||
golang.org/x/crypto v0.51.0
|
||||
golang.org/x/image v0.40.0
|
||||
golang.org/x/net v0.54.0
|
||||
golang.org/x/sync v0.20.0
|
||||
golang.org/x/sys v0.44.0
|
||||
golang.org/x/term v0.43.0
|
||||
golang.org/x/text v0.37.0
|
||||
golang.org/x/crypto v0.53.0
|
||||
golang.org/x/image v0.44.0
|
||||
golang.org/x/net v0.56.0
|
||||
golang.org/x/sync v0.22.0
|
||||
golang.org/x/sys v0.46.0
|
||||
golang.org/x/term v0.44.0
|
||||
golang.org/x/text v0.40.0
|
||||
gopkg.in/mail.v2 v2.3.1
|
||||
)
|
||||
|
||||
@@ -216,8 +216,8 @@ require (
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
go4.org v0.0.0-20260112195520-a5071408f32f // indirect
|
||||
golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect
|
||||
golang.org/x/mod v0.36.0 // indirect
|
||||
golang.org/x/tools v0.45.0 // indirect
|
||||
golang.org/x/mod v0.37.0 // indirect
|
||||
golang.org/x/tools v0.47.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260511170946-3700d4141b60 // indirect
|
||||
google.golang.org/grpc v1.81.0 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
|
||||
+18
-18
@@ -703,13 +703,13 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
|
||||
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
|
||||
golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto=
|
||||
golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a h1:+3jdDGGB8NGb1Zktc737jlt3/A5f6UlwSzmvqUuufxw=
|
||||
golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw=
|
||||
golang.org/x/image v0.40.0 h1:Tw4GyDXMo+daZN1znreBRC3VayR1aLFUyUEOLUdW1a8=
|
||||
golang.org/x/image v0.40.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA=
|
||||
golang.org/x/image v0.44.0 h1:+tDekMZED9+LrtB3G5xzRggpVh9CARjZqROla3R3R+I=
|
||||
golang.org/x/image v0.44.0/go.mod h1:V8K3KE9KKKE+pLpQDOeN18w9oacNSvy1tDOirTu4xtY=
|
||||
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=
|
||||
@@ -719,8 +719,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
|
||||
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
|
||||
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
|
||||
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/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=
|
||||
@@ -747,8 +747,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
|
||||
golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
|
||||
golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
|
||||
golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
|
||||
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=
|
||||
@@ -768,8 +768,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||
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=
|
||||
@@ -805,8 +805,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
|
||||
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
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=
|
||||
@@ -817,8 +817,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
|
||||
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
|
||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||
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=
|
||||
@@ -830,8 +830,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||
golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs=
|
||||
golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY=
|
||||
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.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
@@ -847,8 +847,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
|
||||
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
|
||||
golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q=
|
||||
golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA=
|
||||
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=
|
||||
|
||||
Reference in New Issue
Block a user