ftpd: add basic wildcard support
this is the minimal implementation to allow mget and similar commands with wildcards. We only support wildcard for the last path level, for example: - mget *.xml is supported - mget dir/*.xml is supported - mget */*.xml is not supported Removed . and .. from FTP directory listing Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
9a37e3d159
commit
61947e67ae
6 changed files with 225 additions and 41 deletions
|
@ -57,9 +57,9 @@ func TestBasicFTPHandlingCryptFs(t *testing.T) {
|
||||||
}
|
}
|
||||||
list, err := client.List(".")
|
list, err := client.List(".")
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
assert.Len(t, list, 2)
|
if assert.Len(t, list, 1) {
|
||||||
assert.Equal(t, ".", list[0].Name)
|
assert.Equal(t, testFileSize, int64(list[0].Size))
|
||||||
assert.Equal(t, testFileSize, int64(list[1].Size))
|
}
|
||||||
}
|
}
|
||||||
user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
|
user, _, err = httpdtest.GetUserByUsername(user.Username, http.StatusOK)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
|
@ -550,15 +550,11 @@ func TestBasicFTPHandling(t *testing.T) {
|
||||||
}
|
}
|
||||||
res, err := client.List(path.Join("/", testDir))
|
res, err := client.List(path.Join("/", testDir))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, res, 2) {
|
assert.Len(t, res, 0)
|
||||||
assert.Equal(t, ".", res[0].Name)
|
|
||||||
assert.Equal(t, "..", res[1].Name)
|
|
||||||
}
|
|
||||||
res, err = client.List(path.Join("/"))
|
res, err = client.List(path.Join("/"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.Len(t, res, 2) {
|
if assert.Len(t, res, 1) {
|
||||||
assert.Equal(t, ".", res[0].Name)
|
assert.Equal(t, testDir, res[0].Name)
|
||||||
assert.Equal(t, testDir, res[1].Name)
|
|
||||||
}
|
}
|
||||||
err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
|
err = ftpUploadFile(testFilePath, testFileName, testFileSize, client, 0)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -597,6 +593,105 @@ func TestBasicFTPHandling(t *testing.T) {
|
||||||
50*time.Millisecond)
|
50*time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListDirWithWildcards(t *testing.T) {
|
||||||
|
localUser, _, err := httpdtest.AddUser(getTestUser(), http.StatusCreated)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
sftpUser, _, err := httpdtest.AddUser(getTestSFTPUser(), http.StatusCreated)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
for _, user := range []dataprovider.User{localUser, sftpUser} {
|
||||||
|
client, err := getFTPClient(user, true, nil)
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
dir1 := "test.dir"
|
||||||
|
dir2 := "test.dir1"
|
||||||
|
err = client.MakeDir(dir1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = client.MakeDir(dir2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
testFilePath := filepath.Join(homeBasePath, testFileName)
|
||||||
|
testFileSize := int64(65535)
|
||||||
|
err = createTestFile(testFilePath, testFileSize)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
fileName := "fil*e.dat"
|
||||||
|
err = ftpUploadFile(testFilePath, fileName, testFileSize, client, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
localDownloadPath := filepath.Join(homeBasePath, testDLFileName)
|
||||||
|
err = ftpDownloadFile(fileName, localDownloadPath, testFileSize, client, 0)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
entries, err := client.NameList(fileName)
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assert.Len(t, entries, 1)
|
||||||
|
assert.Contains(t, entries, fileName)
|
||||||
|
}
|
||||||
|
entries, err = client.NameList(".")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, entries, 3)
|
||||||
|
entries, err = client.NameList("/test.*")
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assert.Len(t, entries, 2)
|
||||||
|
assert.Contains(t, entries, dir1)
|
||||||
|
assert.Contains(t, entries, dir2)
|
||||||
|
}
|
||||||
|
entries, err = client.NameList("/*.dir?")
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assert.Len(t, entries, 1)
|
||||||
|
assert.Contains(t, entries, dir2)
|
||||||
|
}
|
||||||
|
entries, err = client.NameList("/test.???")
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assert.Len(t, entries, 1)
|
||||||
|
assert.Contains(t, entries, dir1)
|
||||||
|
}
|
||||||
|
_, err = client.NameList("/missingdir/test.*")
|
||||||
|
assert.Error(t, err)
|
||||||
|
_, err = client.NameList("test[-]")
|
||||||
|
if assert.Error(t, err) {
|
||||||
|
assert.Contains(t, err.Error(), path.ErrBadPattern.Error())
|
||||||
|
}
|
||||||
|
subDir := path.Join(dir1, "sub.d")
|
||||||
|
err = client.MakeDir(subDir)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = client.ChangeDir(path.Dir(subDir))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
entries, err = client.NameList("sub.?")
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assert.Len(t, entries, 1)
|
||||||
|
assert.Contains(t, entries, path.Base(subDir))
|
||||||
|
}
|
||||||
|
entries, err = client.NameList("../*.dir?")
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assert.Len(t, entries, 1)
|
||||||
|
assert.Contains(t, entries, path.Join("../", dir2))
|
||||||
|
}
|
||||||
|
err = client.ChangeDir("/")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
entries, err = client.NameList(path.Join(dir1, "sub.*"))
|
||||||
|
if assert.NoError(t, err) {
|
||||||
|
assert.Len(t, entries, 1)
|
||||||
|
assert.Contains(t, entries, path.Join(dir1, "sub.d"))
|
||||||
|
}
|
||||||
|
err = client.RemoveDir(subDir)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = client.RemoveDir(dir1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = client.RemoveDir(dir2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.Remove(testFilePath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.Remove(localDownloadPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = client.Quit()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = httpdtest.RemoveUser(localUser, http.StatusOK)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
err = os.RemoveAll(localUser.GetHomeDir())
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestStartDirectory(t *testing.T) {
|
func TestStartDirectory(t *testing.T) {
|
||||||
startDir := "/start/dir"
|
startDir := "/start/dir"
|
||||||
u := getTestUser()
|
u := getTestUser()
|
||||||
|
@ -625,12 +720,14 @@ func TestStartDirectory(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
entries, err := client.List(".")
|
entries, err := client.List(".")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, entries, 3)
|
if assert.Len(t, entries, 1) {
|
||||||
|
assert.Equal(t, testFileName, entries[0].Name)
|
||||||
|
}
|
||||||
entries, err = client.List("/")
|
entries, err = client.List("/")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Len(t, entries, 2)
|
if assert.Len(t, entries, 1) {
|
||||||
|
assert.Equal(t, "start", entries[0].Name)
|
||||||
|
}
|
||||||
err = client.ChangeDirToParent()
|
err = client.ChangeDirToParent()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
currentDir, err = client.CurrentDir()
|
currentDir, err = client.CurrentDir()
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
ftpserver "github.com/fclairamb/ftpserverlib"
|
ftpserver "github.com/fclairamb/ftpserverlib"
|
||||||
|
@ -14,7 +15,6 @@ import (
|
||||||
"github.com/drakkan/sftpgo/v2/common"
|
"github.com/drakkan/sftpgo/v2/common"
|
||||||
"github.com/drakkan/sftpgo/v2/dataprovider"
|
"github.com/drakkan/sftpgo/v2/dataprovider"
|
||||||
"github.com/drakkan/sftpgo/v2/logger"
|
"github.com/drakkan/sftpgo/v2/logger"
|
||||||
"github.com/drakkan/sftpgo/v2/util"
|
|
||||||
"github.com/drakkan/sftpgo/v2/vfs"
|
"github.com/drakkan/sftpgo/v2/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -147,6 +147,9 @@ func (c *Connection) Stat(name string) (os.FileInfo, error) {
|
||||||
|
|
||||||
fi, err := c.DoStat(name, 0, true)
|
fi, err := c.DoStat(name, 0, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if c.isListDirWithWildcards(path.Base(name), err) {
|
||||||
|
return vfs.NewFileInfo(name, true, 0, time.Now(), false), nil
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return fi, nil
|
return fi, nil
|
||||||
|
@ -276,13 +279,15 @@ func (c *Connection) ReadDir(name string) ([]os.FileInfo, error) {
|
||||||
|
|
||||||
files, err := c.ListDir(name)
|
files, err := c.ListDir(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return files, err
|
baseName := path.Base(name)
|
||||||
|
if c.isListDirWithWildcards(baseName, err) {
|
||||||
|
// we only support wildcards for the last path level, for example:
|
||||||
|
// - *.xml is supported
|
||||||
|
// - dir*/*.xml is not supported
|
||||||
|
return c.getListDirWithWildcards(path.Dir(name), baseName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if name != "/" {
|
return files, err
|
||||||
files = util.PrependFileInfo(files, vfs.NewFileInfo("..", true, 0, time.Now(), false))
|
|
||||||
}
|
|
||||||
files = util.PrependFileInfo(files, vfs.NewFileInfo(".", true, 0, time.Now(), false))
|
|
||||||
return files, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHandle implements ClientDriverExtentionFileTransfer
|
// GetHandle implements ClientDriverExtentionFileTransfer
|
||||||
|
@ -482,3 +487,56 @@ func (c *Connection) handleFTPUploadToExistingFile(fs vfs.Fs, flags int, resolve
|
||||||
|
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Connection) getListDirWithWildcards(dirName, pattern string) ([]os.FileInfo, error) {
|
||||||
|
files, err := c.ListDir(dirName)
|
||||||
|
if err != nil {
|
||||||
|
return files, err
|
||||||
|
}
|
||||||
|
validIdx := 0
|
||||||
|
relativeBase := getPathRelativeTo(c.clientContext.Path(), dirName)
|
||||||
|
for _, fi := range files {
|
||||||
|
match, err := path.Match(pattern, fi.Name())
|
||||||
|
if err != nil {
|
||||||
|
return files, err
|
||||||
|
}
|
||||||
|
if match {
|
||||||
|
files[validIdx] = vfs.NewFileInfo(path.Join(relativeBase, fi.Name()), fi.IsDir(), fi.Size(),
|
||||||
|
fi.ModTime(), true)
|
||||||
|
validIdx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return files[:validIdx], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) isListDirWithWildcards(name string, err error) bool {
|
||||||
|
if errors.Is(err, c.GetNotExistError()) {
|
||||||
|
lastCommand := c.clientContext.GetLastCommand()
|
||||||
|
if lastCommand == "LIST" || lastCommand == "NLST" {
|
||||||
|
return strings.ContainsAny(name, "*?[]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPathRelativeTo(base, target string) string {
|
||||||
|
var sb strings.Builder
|
||||||
|
for {
|
||||||
|
if base == target {
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(base, "/") {
|
||||||
|
base += "/"
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(target, base) {
|
||||||
|
sb.WriteString(strings.TrimPrefix(target, base))
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
if base == "/" || base == "./" {
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
sb.WriteString("../")
|
||||||
|
base = path.Dir(path.Clean(base))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1002,3 +1002,28 @@ func TestPassiveIPResolver(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, b.ForcePassiveIP, passiveIP)
|
assert.Equal(t, b.ForcePassiveIP, passiveIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRelativePath(t *testing.T) {
|
||||||
|
rel := getPathRelativeTo("/testpath", "/testpath")
|
||||||
|
assert.Empty(t, rel)
|
||||||
|
rel = getPathRelativeTo("/", "/")
|
||||||
|
assert.Empty(t, rel)
|
||||||
|
rel = getPathRelativeTo("/", "/dir/sub")
|
||||||
|
assert.Equal(t, "dir/sub", rel)
|
||||||
|
rel = getPathRelativeTo("./", "/dir/sub")
|
||||||
|
assert.Equal(t, "/dir/sub", rel)
|
||||||
|
rel = getPathRelativeTo("/sub", "/dir/sub")
|
||||||
|
assert.Equal(t, "../dir/sub", rel)
|
||||||
|
rel = getPathRelativeTo("/dir", "/dir/sub")
|
||||||
|
assert.Equal(t, "sub", rel)
|
||||||
|
rel = getPathRelativeTo("/dir/sub", "/dir")
|
||||||
|
assert.Equal(t, "../", rel)
|
||||||
|
rel = getPathRelativeTo("dir", "/dir1")
|
||||||
|
assert.Equal(t, "/dir1", rel)
|
||||||
|
rel = getPathRelativeTo("", "/dir2")
|
||||||
|
assert.Equal(t, "dir2", rel)
|
||||||
|
rel = getPathRelativeTo(".", "/dir2")
|
||||||
|
assert.Equal(t, "/dir2", rel)
|
||||||
|
rel = getPathRelativeTo("/dir3", "dir3")
|
||||||
|
assert.Equal(t, "dir3", rel)
|
||||||
|
}
|
||||||
|
|
16
go.mod
16
go.mod
|
@ -12,9 +12,9 @@ require (
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.4
|
github.com/aws/aws-sdk-go-v2/config v1.15.4
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.0
|
github.com/aws/aws-sdk-go-v2/credentials v1.12.0
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.7
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.8
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.4
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.4
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.7
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.8
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.6
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.6
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.4
|
||||||
github.com/cockroachdb/cockroach-go/v2 v2.2.8
|
github.com/cockroachdb/cockroach-go/v2 v2.2.8
|
||||||
|
@ -65,16 +65,16 @@ require (
|
||||||
go.uber.org/automaxprocs v1.5.1
|
go.uber.org/automaxprocs v1.5.1
|
||||||
gocloud.dev v0.25.0
|
gocloud.dev v0.25.0
|
||||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4
|
||||||
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
|
||||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6
|
||||||
golang.org/x/time v0.0.0-20220411224347-583f2d630306
|
golang.org/x/time v0.0.0-20220411224347-583f2d630306
|
||||||
google.golang.org/api v0.77.0
|
google.golang.org/api v0.78.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go v0.101.0 // indirect
|
cloud.google.com/go v0.101.1 // indirect
|
||||||
cloud.google.com/go/compute v1.6.1 // indirect
|
cloud.google.com/go/compute v1.6.1 // indirect
|
||||||
cloud.google.com/go/iam v0.3.0 // indirect
|
cloud.google.com/go/iam v0.3.0 // indirect
|
||||||
github.com/Azure/azure-sdk-for-go/sdk/internal v0.9.2 // indirect
|
github.com/Azure/azure-sdk-for-go/sdk/internal v0.9.2 // indirect
|
||||||
|
@ -152,7 +152,7 @@ require (
|
||||||
golang.org/x/tools v0.1.10 // indirect
|
golang.org/x/tools v0.1.10 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e // indirect
|
google.golang.org/genproto v0.0.0-20220504150022-98cd25cafc72 // indirect
|
||||||
google.golang.org/grpc v1.46.0 // indirect
|
google.golang.org/grpc v1.46.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||||
|
@ -164,5 +164,5 @@ require (
|
||||||
replace (
|
replace (
|
||||||
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
|
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
|
||||||
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20220412172350-e76a61f8e7d2
|
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20220412172350-e76a61f8e7d2
|
||||||
golang.org/x/net => github.com/drakkan/net v0.0.0-20220425150817-e26421ba5d2e
|
golang.org/x/net => github.com/drakkan/net v0.0.0-20220504073018-5d1702f4106f
|
||||||
)
|
)
|
||||||
|
|
28
go.sum
28
go.sum
|
@ -31,8 +31,8 @@ cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Ud
|
||||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||||
cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
|
cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U=
|
||||||
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||||
cloud.google.com/go v0.101.0 h1:g+LL+JvpvdyGtcaD2xw2mSByE/6F9s471eJSoaysM84=
|
cloud.google.com/go v0.101.1 h1:3+/0TAm9JD/PyhkrDWQWi2L197h3euCsM+H+J4iYTR8=
|
||||||
cloud.google.com/go v0.101.0/go.mod h1:hEiddgDb77jDQ+I80tURYNJEnuwPzFU8awCFFRLKjW0=
|
cloud.google.com/go v0.101.1/go.mod h1:55HwjsGW4CHD3JrNuMdZtSDsgTs0CuCB/bBTugD+7AA=
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||||
|
@ -150,8 +150,8 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnq
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 h1:FP8gquGeGHHdfY6G5llaMQDF+HAf20VKc8opRwmjf04=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4 h1:FP8gquGeGHHdfY6G5llaMQDF+HAf20VKc8opRwmjf04=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4/go.mod h1:u/s5/Z+ohUQOPXl00m2yJVyioWDECsbpXTQlaqSlufc=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.4/go.mod h1:u/s5/Z+ohUQOPXl00m2yJVyioWDECsbpXTQlaqSlufc=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.7 h1:h1y9Jn+1VTEjB4TG5prxtQjW9DM5o8y7Cu9ZdNmkXWA=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.8 h1:DrnslKj0yz31roe7+tmMblGhbr6OV7VQUJo5ylBU9YQ=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.7/go.mod h1:NZ2wPktB/I111CyzF3ezVf8jrAg/PqKeYkdR11oBWeU=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.8/go.mod h1:PCN2NuDpHRYLcO2Gl9yVToeahcRBkf+87inUVGwtM+Q=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 h1:uFWgo6mGJI1n17nbcvSc6fxVuR3xLNqvXt12JCnEcT8=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10 h1:uFWgo6mGJI1n17nbcvSc6fxVuR3xLNqvXt12JCnEcT8=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10/go.mod h1:F+EZtuIwjlv35kRJPyBGcsA4f7bnSoz15zOQ2lJq1Z4=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10/go.mod h1:F+EZtuIwjlv35kRJPyBGcsA4f7bnSoz15zOQ2lJq1Z4=
|
||||||
|
@ -178,8 +178,8 @@ github.com/aws/aws-sdk-go-v2/service/kms v1.16.3/go.mod h1:QuiHPBqlOFCi4LqdSskYY
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.4 h1:qmHavnjRtgdH54nyG4iEk6ZCde9m2S++32INurhaNTk=
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.4 h1:qmHavnjRtgdH54nyG4iEk6ZCde9m2S++32INurhaNTk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.4/go.mod h1:CloMDruFIVZJ8qv2OsY5ENIqzg5c0eeTciVVW3KHdvE=
|
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.4/go.mod h1:CloMDruFIVZJ8qv2OsY5ENIqzg5c0eeTciVVW3KHdvE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3/go.mod h1:g1qvDuRsJY+XghsV6zg00Z4KJ7DtFFCx8fJD2a491Ak=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3/go.mod h1:g1qvDuRsJY+XghsV6zg00Z4KJ7DtFFCx8fJD2a491Ak=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.7 h1:ZEPH6aBywdyn5LGr7hSNEwuPaKpKZodX0R9AjPj5A7c=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.8 h1:XInp7WokGrNBYC+5rm9npWC0vrF2xtfNfM/qozGI6U0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.7/go.mod h1:iMYipLPXlWpBJ0KFX7QJHZ84rBydHBY8as2aQICTPWk=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.8/go.mod h1:iMYipLPXlWpBJ0KFX7QJHZ84rBydHBY8as2aQICTPWk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.4/go.mod h1:PJc8s+lxyU8rrre0/4a0pn2wgwiDvOEzoOjcJUBr67o=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.4/go.mod h1:PJc8s+lxyU8rrre0/4a0pn2wgwiDvOEzoOjcJUBr67o=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.6 h1:m+mxqLIrGq7GJo5qw4rHn8BbUqHrvxvwFx54N1Pglvw=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.6 h1:m+mxqLIrGq7GJo5qw4rHn8BbUqHrvxvwFx54N1Pglvw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.6/go.mod h1:Z+i6uqZgCOBXhNoEGoRm/ZaLsaJA9rGUAmkVKM/3+g4=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.6/go.mod h1:Z+i6uqZgCOBXhNoEGoRm/ZaLsaJA9rGUAmkVKM/3+g4=
|
||||||
|
@ -255,8 +255,8 @@ github.com/drakkan/crypto v0.0.0-20220412172350-e76a61f8e7d2 h1:5XmEywX1u5gPgOC+
|
||||||
github.com/drakkan/crypto v0.0.0-20220412172350-e76a61f8e7d2/go.mod h1:SiM6ypd8Xu1xldObYtbDztuUU7xUzMnUULfphXFZmro=
|
github.com/drakkan/crypto v0.0.0-20220412172350-e76a61f8e7d2/go.mod h1:SiM6ypd8Xu1xldObYtbDztuUU7xUzMnUULfphXFZmro=
|
||||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
|
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
|
||||||
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
|
||||||
github.com/drakkan/net v0.0.0-20220425150817-e26421ba5d2e h1:QCodCQfdiYnXHR+1nnzi69+tM6FEThtzthP8ZhpHkrk=
|
github.com/drakkan/net v0.0.0-20220504073018-5d1702f4106f h1:BUIQ/l47ZPdruH1S17AdCCq6YNR/DyLpvysRXikD/Xg=
|
||||||
github.com/drakkan/net v0.0.0-20220425150817-e26421ba5d2e/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
github.com/drakkan/net v0.0.0-20220504073018-5d1702f4106f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 h1:/ZshrfQzayqRSBDodmp3rhNCHJCff+utvgBuWRbiqu4=
|
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 h1:/ZshrfQzayqRSBDodmp3rhNCHJCff+utvgBuWRbiqu4=
|
||||||
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001/go.mod h1:kltMsfRMTHSFdMbK66XdS8mfMW77+FZA1fGY1xYMF84=
|
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001/go.mod h1:kltMsfRMTHSFdMbK66XdS8mfMW77+FZA1fGY1xYMF84=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
@ -965,8 +965,9 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/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-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32 h1:Js08h5hqB5xyWR789+QqueR6sDE8mk+YvpETZ+F6X9Y=
|
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||||
|
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
@ -1102,8 +1103,9 @@ google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/S
|
||||||
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
|
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
|
||||||
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
||||||
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||||
google.golang.org/api v0.77.0 h1:msijLTxwkJ7Jub5tv9KBVCKtHOQwnvnvkX7ErFFCVxY=
|
|
||||||
google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||||
|
google.golang.org/api v0.78.0 h1:5ewPyCwP43C3i8B6C2Kb+eVAevbnke2xR8VbcSWjS4I=
|
||||||
|
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
@ -1203,8 +1205,10 @@ google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX
|
||||||
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e h1:gMjH4zLGs9m+dGzR7qHCHaXMOwsJHJKKkHtyXhtOrJk=
|
|
||||||
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||||
|
google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
|
google.golang.org/genproto v0.0.0-20220504150022-98cd25cafc72 h1:iif0mpUetMBqcQPUoq+JnCcmzvfpp8wRx515va8wP1c=
|
||||||
|
google.golang.org/genproto v0.0.0-20220504150022-98cd25cafc72/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
|
Loading…
Reference in a new issue