From 6f422c3d8b7f357ecbaa4075f5e43b1ade83bdce Mon Sep 17 00:00:00 2001 From: Nicola Murino Date: Thu, 27 Oct 2022 08:27:44 +0200 Subject: [PATCH] WebClient: make folder deletion recursive Signed-off-by: Nicola Murino --- go.mod | 67 +++++++------- go.sum | 136 ++++++++++++++-------------- internal/common/connection.go | 138 ++++++++++++++++++++++++++++- internal/common/connection_test.go | 128 +++++++++++++++++++++++++- internal/common/protocol_test.go | 75 ++++++++++++++++ internal/common/transfer_test.go | 2 +- internal/httpd/api_http_user.go | 6 +- internal/webdavd/handler.go | 124 +------------------------- internal/webdavd/internal_test.go | 137 ++-------------------------- templates/webclient/files.html | 4 +- 10 files changed, 453 insertions(+), 364 deletions(-) diff --git a/go.mod b/go.mod index a36289c5..7d895870 100644 --- a/go.mod +++ b/go.mod @@ -8,15 +8,15 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.5.1 github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 - github.com/aws/aws-sdk-go-v2 v1.17.0 - github.com/aws/aws-sdk-go-v2/config v1.17.9 - github.com/aws/aws-sdk-go-v2/credentials v1.12.22 - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.18 - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.36 - github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.20 - github.com/aws/aws-sdk-go-v2/service/s3 v1.29.0 - github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.3 - github.com/aws/aws-sdk-go-v2/service/sts v1.17.0 + github.com/aws/aws-sdk-go-v2 v1.17.1 + github.com/aws/aws-sdk-go-v2/config v1.17.10 + github.com/aws/aws-sdk-go-v2/credentials v1.12.23 + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37 + github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.21 + github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.4 + github.com/aws/aws-sdk-go-v2/service/sts v1.17.1 github.com/cockroachdb/cockroach-go/v2 v2.2.16 github.com/coreos/go-oidc/v3 v3.4.0 github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 @@ -34,12 +34,12 @@ require ( github.com/hashicorp/go-hclog v1.3.1 github.com/hashicorp/go-plugin v1.4.5 github.com/hashicorp/go-retryablehttp v0.7.1 - github.com/jackc/pgx/v5 v5.0.4-0.20221022150232-3e825ec8982f + github.com/jackc/pgx/v5 v5.0.4 github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126 - github.com/klauspost/compress v1.15.11 + github.com/klauspost/compress v1.15.12 github.com/lestrrat-go/jwx v1.2.25 github.com/lithammer/shortuuid/v3 v3.0.7 - github.com/mattn/go-sqlite3 v1.14.15 + github.com/mattn/go-sqlite3 v1.14.16 github.com/mhale/smtpd v0.8.0 github.com/minio/sio v0.3.0 github.com/otiai10/copy v1.7.0 @@ -54,9 +54,9 @@ require ( github.com/sftpgo/sdk v0.1.2 github.com/shirou/gopsutil/v3 v3.22.9 github.com/spf13/afero v1.9.2 - github.com/spf13/cobra v1.6.0 + github.com/spf13/cobra v1.6.1 github.com/spf13/viper v1.13.0 - github.com/stretchr/testify v1.8.0 + github.com/stretchr/testify v1.8.1 github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423 github.com/subosito/gotenv v1.4.1 github.com/unrolled/secure v1.13.0 @@ -71,28 +71,29 @@ require ( golang.org/x/oauth2 v0.1.0 golang.org/x/sys v0.1.0 golang.org/x/time v0.1.0 - google.golang.org/api v0.100.0 + google.golang.org/api v0.101.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 ) require ( - cloud.google.com/go v0.104.0 // indirect - cloud.google.com/go/compute v1.10.0 // indirect - cloud.google.com/go/iam v0.5.0 // indirect + cloud.google.com/go v0.105.0 // indirect + cloud.google.com/go/compute v1.12.1 // indirect + cloud.google.com/go/compute/metadata v0.1.1 // indirect + cloud.google.com/go/iam v0.6.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.1 // indirect github.com/ajg/form v1.5.1 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.24 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.18 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.25 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.15 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.19 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.18 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.18 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.11.24 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.7 // indirect - github.com/aws/smithy-go v1.13.3 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect + github.com/aws/smithy-go v1.13.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect @@ -131,7 +132,7 @@ require ( github.com/magiconair/properties v1.8.6 // 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.2 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/miekg/dns v1.1.50 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -159,7 +160,7 @@ require ( golang.org/x/tools v0.2.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 // indirect + google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 // indirect google.golang.org/grpc v1.50.1 // indirect google.golang.org/protobuf v1.28.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -171,5 +172,5 @@ require ( replace ( github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20221020054403-a265c1cba3cb - golang.org/x/net => github.com/drakkan/net v0.0.0-20221020052826-79457e688bf9 + golang.org/x/net => github.com/drakkan/net v0.0.0-20221026175805-eaebd725b308 ) diff --git a/go.sum b/go.sum index ebee9238..c734580c 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9 cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= cloud.google.com/go v0.103.0/go.mod h1:vwLx1nqLrzLX/fpwSMOXmFIqBOyHsvHbnAdbGSJ+mKk= -cloud.google.com/go v0.104.0 h1:gSmWO7DY1vOm0MVU6DNXM11BWHHsTUmsC5cv1fuW5X8= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= +cloud.google.com/go v0.105.0 h1:DNtEKRBAAzeS4KyIory52wWHuClNaXJ5x1F7xa4q+5Y= +cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -50,16 +50,18 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0 h1:aoLIYaA1fX3ywihqpBk2APQKOo20nXsp1GEZQbx5Jk4= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= +cloud.google.com/go/compute v1.12.1 h1:gKVJMEyqV5c/UnpzjjQbo3Rjvvqpr9B1DFSbJC4OXr0= +cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= +cloud.google.com/go/compute/metadata v0.1.1 h1:/sxEbyrm6cw+XOUw1YxBHlatV71z4vpnmO7z2IZ0h3I= +cloud.google.com/go/compute/metadata v0.1.1/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0 h1:fz9X5zyTWBmamZsqvqZqD7khbifcZF/q+Z1J8pfhIUg= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= +cloud.google.com/go/iam v0.6.0 h1:nsqQC88kT5Iwlm4MeNGTpfMWddp6NB/UOLFTH6m1QfQ= +cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= cloud.google.com/go/kms v1.4.0 h1:iElbfoE61VeLhnZcGOltqL8HIly8Nhbe5t6JlH9GXjo= cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TElyanS95vIcl4= @@ -224,70 +226,70 @@ github.com/aws/aws-sdk-go v1.44.45/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4 github.com/aws/aws-sdk-go v1.44.68/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.16.8/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= -github.com/aws/aws-sdk-go-v2 v1.17.0 h1:kWm8OZGx0Zvd6PsOfjFtwbw7+uWYp65DK8suo7WVznw= -github.com/aws/aws-sdk-go-v2 v1.17.0/go.mod h1:SwiyXi/1zTUZ6KIAmLK5V5ll8SiURNUYOqTerZPaF9k= +github.com/aws/aws-sdk-go-v2 v1.17.1 h1:02c72fDJr87N8RAC2s3Qu0YuvMRZKNZJ9F+lAehCazk= +github.com/aws/aws-sdk-go-v2 v1.17.1/go.mod h1:JLnGeGONAyi2lWXI1p0PCIOIy333JMVK1U7Hf0aRFLw= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8 h1:tcFliCWne+zOuUfKNRn8JdFBuWPDuISDH08wD2ULkhk= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.8/go.mod h1:JTnlBSot91steJeti4ryyu/tLd4Sk84O5W22L7O2EQU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 h1:RKci2D7tMwpvGpDNZnGQw9wk6v7o/xSwFcUAuNPoB8k= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9/go.mod h1:vCmV1q1VK8eoQJ5+aYE7PkK1K6v41qJ5pJdK3ggCDvg= github.com/aws/aws-sdk-go-v2/config v1.15.15/go.mod h1:A1Lzyy/o21I5/s2FbyX5AevQfSVXpvvIDCoVFD0BC4E= -github.com/aws/aws-sdk-go-v2/config v1.17.9 h1:PyqFD7DTmOx5gdvjFwZH2Tx0vivy+cJdM3SE3NVoWZc= -github.com/aws/aws-sdk-go-v2/config v1.17.9/go.mod h1:NGC2Ut1x1Gl+qBdh4uGdqRTDtk6f3qS8VQ45kEoyAvM= +github.com/aws/aws-sdk-go-v2/config v1.17.10 h1:zBy5QQ/mkvHElM1rygHPAzuH+sl8nsdSaxSWj0+rpdE= +github.com/aws/aws-sdk-go-v2/config v1.17.10/go.mod h1:/4np+UiJJKpWHN7Q+LZvqXYgyjgeXm5+lLfDI6TPZao= github.com/aws/aws-sdk-go-v2/credentials v1.12.10/go.mod h1:g5eIM5XRs/OzIIK81QMBl+dAuDyoLN0VYaLP+tBqEOk= -github.com/aws/aws-sdk-go-v2/credentials v1.12.22 h1:HPig9ugqH7Eyf2aqNVAPOCp3L/N2vlQ/IiaTxwcrH8U= -github.com/aws/aws-sdk-go-v2/credentials v1.12.22/go.mod h1:XfHZqa+J1j2Am2GHrsWtg24tnkFkKxmWbWWel+W1zp0= +github.com/aws/aws-sdk-go-v2/credentials v1.12.23 h1:LctvcJMIb8pxvk5hQhChpCu0WlU6oKQmcYb1HA4IZSA= +github.com/aws/aws-sdk-go-v2/credentials v1.12.23/go.mod h1:0awX9iRr/+UO7OwRQFpV1hNtXxOVuehpjVEzrIAYNcA= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9/go.mod h1:KDCCm4ONIdHtUloDcFvK2+vshZvx4Zmj7UMDfusuz5s= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.18 h1:63dqlW4EI4nfhmXJOUqP0zIaGEHoRPn1ahLz8hUOWrQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.18/go.mod h1:O3tSoDcot3jy62HNmq7ms16dPHQMR6nqQxooj8T53tI= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 h1:E3PXZSI3F2bzyj6XxUXdTIfvp425HHhwKsFvmzBwHgs= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19/go.mod h1:VihW95zQpeKQWVPGkwT+2+WJNQV8UXFfMTWdU6VErL8= github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.21/go.mod h1:iIYPrQ2rYfZiB/iADYlhj9HHZ9TTi6PqKQPAqygohbE= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.36 h1:DYIvpSIM9YTdid6yRZk/w2kJhJJIbFnL/76NfzmfaTs= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.36/go.mod h1:1vzWYwKGRitVzk7xD3y8Ko7lg26qX+Pxwb5uRaOPSlM= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37 h1:e1VtTBo+cLNjres0wTlMkmwCGGRjDEkkrz3frxxcaCs= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.37/go.mod h1:kdAV1UMnCkyG6tZJUC4mHbPoRjPA3dIK0L8mnsHERiM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.24 h1:WFIoN2kiF95/4z4HNcJ9F9B0xFV0vrPlUOf3+uNIujM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.24/go.mod h1:ghMzB/j2wRbPx5/4jPYxJdOtCG2ggrtY01j8K7FMBDA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25 h1:nBO/RFxeq/IS5G9Of+ZrgucRciie2qpLy++3UGZ+q2E= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.25/go.mod h1:Zb29PYkf42vVYQY6pvSyJCJcFHlPIiY+YKdPtwnvMkY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.9/go.mod h1:08tUpeSGN33QKSO7fwxXczNfiwCpbj+GxK6XKwqWVv0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.18 h1:c2RKF0UvfdVI6epHtFjDujlbiK+VeY85dP1i4gmYc5w= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.18/go.mod h1:fkQKYK/jUhCL/wNS1tOPrlYhr9vqutjCz4zZC1wBE1s= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19 h1:oRHDrwCTVT8ZXi4sr9Ld+EXk7N/KGssOr2ygNeojEhw= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.19/go.mod h1:6Q0546uHDp421okhmmGfbxzq2hBqbXFNpi4k+Q1JnQA= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.16/go.mod h1:CYmI+7x03jjJih8kBEEFKRQc40UjUokT0k7GbvrhhTc= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.25 h1:q4TXoep+lPTJneYxlIdcBrlGmTrhfNwrfkdBt1+HqzA= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.25/go.mod h1:9uX0Ksj6Zmsd3iQIyVkwkPWUqhPF6TxT/t8zYwUiQEU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26 h1:Mza+vlnZr+fPKFKRq/lKGVvM6B/8ZZmNdEopOwSQLms= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.26/go.mod h1:Y2OJ+P+MC1u1VKnavT+PshiEuGPyh/7DqxoDNij4/bg= github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.6/go.mod h1:O7Oc4peGZDEKlddivslfYFvAbgzvl/GH3J8j3JIGBXc= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.15 h1:15q0OjFjny5qjCC8nI+4DH+MZFDC2/BtXxONBNnVZR8= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.15/go.mod h1:t7/Pw0mlxveHXyfzEkGjzQ59Xu9xUmzOfxe1S52TJ8Q= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16 h1:2EXB7dtGwRYIN3XQ9qwIW504DVbKIw3r89xQnonGdsQ= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.16/go.mod h1:XH+3h395e3WVdd6T2Z3mPxuI+x/HVtdqVOREkTiyubs= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3/go.mod h1:gkb2qADY+OHaGLKNTYxMaQNacfeyQpZ4csDTQMeFmcw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9 h1:Lh1AShsuIJTwMkoxVCAYPJgNG5H+eN6SmoUn8nOZ5wE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.9/go.mod h1:a9j48l6yL5XINLHLcOKInjdvknN+vWqPBxqeIDw7ktw= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10 h1:dpiPHgmFstgkLG07KaYAewvuptq5kvo52xn7tVSrtrQ= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.10/go.mod h1:9cBNUHI2aW4ho0A5T87O294iPDuuUOSIEDjnd1Lq/z0= github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.10/go.mod h1:Qks+dxK3O+Z2deAhNo6cJ8ls1bam3tUGUAcgxQP1c70= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.19 h1:jrV+VRNrUuzcwTZxdZMi1JtKMk71FN1H7VaF8XjGl44= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.19/go.mod h1:HGDDjLf/IyINXk4PcEZSEviZulqnePG76iq9/rC5qqo= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20 h1:KSvtm1+fPXE0swe9GPjc6msyrdTT0LB/BP8eLugL1FI= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.20/go.mod h1:Mp4XI/CkWGD79AQxZ5lIFlgvC0A+gl+4BmyG1F+SfNc= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.9/go.mod h1:yQowTpvdZkFVuHrLBXmczat4W+WJKg/PafBZnGBLga0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.18 h1:5oiCDEOHnYkk7uTVI8Wv6ftdFfb6YlUUNzkeePVIPjY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.18/go.mod h1:QtCDHDOXunxeihz7iU15e09u9gRIeaa5WeE6FZVnGUo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19 h1:GE25AWCdNUPh9AOJzI9KIJnja7IwUc1WyUqz/JTyJ/I= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.19/go.mod h1:02CP6iuYP+IVnBX5HULVdSAku/85eHB2Y9EsFhrkEwU= github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.9/go.mod h1:Rc5+wn2k8gFSi3V1Ch4mhxOzjMh+bYSXVFfVaqowQOY= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.18 h1:sk9Z5ZwZpLGq3q8ZhOsw8bORT2t8raWPsFrq/yMMbZ0= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.18/go.mod h1:O1mfO/JzWKUNujOAqD39r7BXqlvhjh/JiPnQ97tvQMc= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 h1:piDBAaWkaxkkVV3xJJbTehXCZRXYs49kvpi/LG6LR2o= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19/go.mod h1:BmQWRVkLTmyNzYPFAZgon53qKLWBNSvonugD1MrSWUs= github.com/aws/aws-sdk-go-v2/service/kms v1.18.1/go.mod h1:4PZMUkc9rXHWGVB5J9vKaZy3D7Nai79ORworQ3ASMiM= -github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.20 h1:jOpM3C6a/W4cd31hj3qok1NZKu3pWYLEg5IwUharV+o= -github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.20/go.mod h1:pvYIQ3quYKA9wXvn5oY6Suu4RqjURwN1tERJssL57nQ= +github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.21 h1:LpIut7TpOhp8RuTD72PBj8ksPy3+RelT3LPwGgQ8+Hg= +github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.13.21/go.mod h1:mRGY+k3s1yt7yQA3AfzJhnr68OCs1xDfQfIABFUk+ek= github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2/go.mod h1:u+566cosFI+d+motIz3USXEh6sN8Nq4GrNXSg2RXVMo= -github.com/aws/aws-sdk-go-v2/service/s3 v1.29.0 h1:wmROdhyusq7m7HJgSB9Jm955XU4Kvz0FknIbr1dJTjA= -github.com/aws/aws-sdk-go-v2/service/s3 v1.29.0/go.mod h1:syhASH3D6eA1PCga49mGfvISJh/E2QYaooSIqir3pIM= +github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1 h1:/EMdFPW/Ppieh0WUtQf1+qCGNLdsq5UWUyevBQ6vMVc= +github.com/aws/aws-sdk-go-v2/service/s3 v1.29.1/go.mod h1:/NHbqPRiwxSPVOB2Xr+StDEH+GWV/64WwnUjv4KYzV0= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.14/go.mod h1:xakbH8KMsQQKqzX87uyyzTHshc/0/Df8bsTneTS5pFU= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.3 h1:d5S+OhXne5O3cIo999RARy/N1dgXW2ldWgD53qbEAP4= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.3/go.mod h1:+X/VSQcuvHPWPRlM64HoWUJAPwsD86KpU9Z52lrsodM= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.4 h1:Hx79EGrkKNJya2iz2U5A7nyr7DjOu/TGTRefThfBZ1w= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.16.4/go.mod h1:k6CPuxyzO247nYEM1baEwHH1kRtosRCvgahAepaaShw= github.com/aws/aws-sdk-go-v2/service/sns v1.17.10/go.mod h1:uITsRNVMeCB3MkWpXxXw0eDz8pW4TYLzj+eyQtbhSxM= github.com/aws/aws-sdk-go-v2/service/sqs v1.19.1/go.mod h1:A94o564Gj+Yn+7QO1eLFeI7UVv3riy/YBFOfICVqFvU= github.com/aws/aws-sdk-go-v2/service/ssm v1.27.6/go.mod h1:fiFzQgj4xNOg4/wqmAiPvzgDMXPD+cUEplX/CYn+0j0= github.com/aws/aws-sdk-go-v2/service/sso v1.11.13/go.mod h1:d7ptRksDDgvXaUvxyHZ9SYh+iMDymm94JbVcgvSYSzU= -github.com/aws/aws-sdk-go-v2/service/sso v1.11.24 h1:tNfD0JI7VKcIcEzYeIAXCIr8qnoq6DACg3QRt50ofOY= -github.com/aws/aws-sdk-go-v2/service/sso v1.11.24/go.mod h1:7ZC+G3rX2IsGKIhiGDFiul7rgZPApvFy3dDJO7wKtno= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.7 h1:q2FDE8cl8rTPqgrTT0dF7xzIfGAwLMh2P+nU7F2CqVs= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.7/go.mod h1:sPh8yf7vmBOI/L9fqP55uq+T9WVoxnqrHMqyvgYC/gA= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 h1:GFZitO48N/7EsFDt8fMa5iYdmWqkUDDB3Eje6z3kbG0= +github.com/aws/aws-sdk-go-v2/service/sso v1.11.25/go.mod h1:IARHuzTXmj1C0KS35vboR0FeJ89OkEy1M9mWbK2ifCI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 h1:jcw6kKZrtNfBPJkaHrscDOZoe5gvi9wjudnxvozYFJo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8/go.mod h1:er2JHN+kBY6FcMfcBBKNGCT3CarImmdFzishsqBmSRI= github.com/aws/aws-sdk-go-v2/service/sts v1.16.10/go.mod h1:cftkHYN6tCDNfkSasAmclSfl4l7cySoay8vz7p/ce0E= -github.com/aws/aws-sdk-go-v2/service/sts v1.17.0 h1:9S0HcZUxKcU3HdN+M6GgLIvdbg9as5aOoHrvwRsPNYU= -github.com/aws/aws-sdk-go-v2/service/sts v1.17.0/go.mod h1:9pZN58zQc5a4Dkdnhu/rI1lNBui1vP5B0giGCuUt2b0= +github.com/aws/aws-sdk-go-v2/service/sts v1.17.1 h1:KRAix/KHvjGODaHAMXnxRk9t0D+4IJVUuS/uwXxngXk= +github.com/aws/aws-sdk-go-v2/service/sts v1.17.1/go.mod h1:bXcN3koeVYiJcdDU89n3kCYILob7Y34AeLopUbZgLT4= github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.13.3 h1:l7LYxGuzK6/K+NzJ2mC+VvLUbae0sL3bXU//04MkmnA= -github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.13.4 h1:/RN2z1txIJWeXeOkzX+Hk/4Uuvv7dWtCjbmVJcrskyk= +github.com/aws/smithy-go v1.13.4/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= 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/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -539,8 +541,8 @@ github.com/drakkan/crypto v0.0.0-20221020054403-a265c1cba3cb h1:ex3x8ir969oV6bQ8 github.com/drakkan/crypto v0.0.0-20221020054403-a265c1cba3cb/go.mod h1:IBSs4ri4rdTqz2QKcpTKpwKMdM+WJ7atZeL9lCu2swQ= 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/net v0.0.0-20221020052826-79457e688bf9 h1:vU78OwgLgNqWDqhsk9So0XtQrPxgMDs85L+A3YotXIA= -github.com/drakkan/net v0.0.0-20221020052826-79457e688bf9/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +github.com/drakkan/net v0.0.0-20221026175805-eaebd725b308 h1:F7OUb3MgSa2SuY5mdmseihGXhVhxv1OCuKHrona2eh0= +github.com/drakkan/net v0.0.0-20221026175805-eaebd725b308/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -1013,8 +1015,8 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= -github.com/jackc/pgx/v5 v5.0.4-0.20221022150232-3e825ec8982f h1:DEdjdZkMfuJ9Y9sELu1idpOg7101O6YlpdnSXlh0Et8= -github.com/jackc/pgx/v5 v5.0.4-0.20221022150232-3e825ec8982f/go.mod h1:U0ynklHtgg43fue9Ly30w3OCSTDPlXjig9ghrNGaguQ= +github.com/jackc/pgx/v5 v5.0.4 h1:r5O6y84qHX/z/HZV40JBdx2obsHz7/uRj5b+CcYEdeY= +github.com/jackc/pgx/v5 v5.0.4/go.mod h1:U0ynklHtgg43fue9Ly30w3OCSTDPlXjig9ghrNGaguQ= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -1060,8 +1062,8 @@ github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYs github.com/klauspost/compress v1.11.13/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.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= -github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= +github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.1.2 h1:XhdX4fqAJUA0yj+kUwMavO0hHrSPAecYdYf1ZmxHvak= github.com/klauspost/cpuid/v2 v2.1.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= @@ -1161,12 +1163,12 @@ github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vq github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/matttproud/golang_protobuf_extensions v1.0.2 h1:hAHbPm5IJGijwng3PWk09JkG9WeqChjprR5s9bBZ+OM= -github.com/matttproud/golang_protobuf_extensions v1.0.2/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/mhale/smtpd v0.8.0 h1:5JvdsehCg33PQrZBvFyDMMUDQmvbzVpZgKob7eYBJc0= github.com/mhale/smtpd v0.8.0/go.mod h1:MQl+y2hwIEQCXtNhe5+55n0GZOjSmeqORDIXbqUL3x4= @@ -1494,8 +1496,8 @@ github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKv github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= -github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -1519,6 +1521,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1529,8 +1532,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423 h1:Wd8WDEEusB5+En4PiRWJp1cP59QLNsQun+mOTW8+s6s= github.com/studio-b12/gowebdav v0.0.0-20221015232716-17255f2e7423/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= @@ -1783,7 +1787,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= 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= @@ -2104,8 +2108,8 @@ google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6F google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= google.golang.org/api v0.91.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.100.0 h1:LGUYIrbW9pzYQQ8NWXlaIVkgnfubVBZbMFb9P8TK374= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= +google.golang.org/api v0.101.0 h1:lJPPeEBIRxGpGLwnBTam1NPEM8Z2BmmXEd3z812pjwM= +google.golang.org/api v0.101.0/go.mod h1:CjxAAWWt3A3VrUE2IGDY2bgK5qhoG/OkyWVlYcP05MY= 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.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2216,8 +2220,8 @@ google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljW google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55 h1:U1u4KB2kx6KR/aJDjQ97hZ15wQs8ZPvDcGcRynBhkvg= -google.golang.org/genproto v0.0.0-20221018160656-63c7b68cfc55/go.mod h1:45EK0dUbEZ2NHjCeAd2LXmyjAgGUGrpGROgjhC3ADck= +google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 h1:GEgb2jF5zxsFJpJfg9RoDDWm7tiwc/DDSTE2BtLUkXU= +google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 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= diff --git a/internal/common/connection.go b/internal/common/connection.go index 15f0a0c1..52824b54 100644 --- a/internal/common/connection.go +++ b/internal/common/connection.go @@ -462,7 +462,7 @@ func (c *BaseConnection) RemoveDir(virtualPath string) error { return c.GetFsError(fs, err) } if !fi.IsDir() || fi.Mode()&os.ModeSymlink != 0 { - c.Log(logger.LevelError, "cannot remove %#v is not a directory", fsPath) + c.Log(logger.LevelError, "cannot remove %q is not a directory", fsPath) return c.GetGenericError(nil) } @@ -477,6 +477,132 @@ func (c *BaseConnection) RemoveDir(virtualPath string) error { return nil } +type objectToRemoveMapping struct { + fsPath string + virtualPath string + info os.FileInfo +} + +// orderDirsToRemove orders directories so that the empty ones will be at slice start +func orderDirsToRemove(fs vfs.Fs, dirsToRemove []objectToRemoveMapping) []objectToRemoveMapping { + orderedDirs := make([]objectToRemoveMapping, 0, len(dirsToRemove)) + removedDirs := make([]string, 0, len(dirsToRemove)) + + pathSeparator := "/" + if vfs.IsLocalOsFs(fs) { + pathSeparator = string(os.PathSeparator) + } + + for len(orderedDirs) < len(dirsToRemove) { + for idx, d := range dirsToRemove { + if util.Contains(removedDirs, d.fsPath) { + continue + } + isEmpty := true + for idx1, d1 := range dirsToRemove { + if idx == idx1 { + continue + } + if util.Contains(removedDirs, d1.fsPath) { + continue + } + if strings.HasPrefix(d1.fsPath, d.fsPath+pathSeparator) { + isEmpty = false + break + } + } + if isEmpty { + orderedDirs = append(orderedDirs, d) + removedDirs = append(removedDirs, d.fsPath) + } + } + } + + return orderedDirs +} + +func (c *BaseConnection) removeDirTree(fs vfs.Fs, fsPath, virtualPath string) error { + var dirsToRemove []objectToRemoveMapping + var filesToRemove []objectToRemoveMapping + + err := fs.Walk(fsPath, func(walkedPath string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + obj := objectToRemoveMapping{ + fsPath: walkedPath, + virtualPath: fs.GetRelativePath(walkedPath), + info: info, + } + if info.IsDir() { + err = c.IsRemoveDirAllowed(fs, obj.fsPath, obj.virtualPath) + isDuplicated := false + for _, d := range dirsToRemove { + if d.fsPath == obj.fsPath { + isDuplicated = true + break + } + } + if !isDuplicated { + dirsToRemove = append(dirsToRemove, obj) + } + } else { + err = c.IsRemoveFileAllowed(obj.virtualPath) + filesToRemove = append(filesToRemove, obj) + } + if err != nil { + c.Log(logger.LevelError, "unable to remove dir tree, object %q->%q cannot be removed: %v", + virtualPath, fsPath, err) + return err + } + + return nil + }) + if err != nil { + c.Log(logger.LevelError, "failed to remove dir tree %q->%q: error: %+v", virtualPath, fsPath, err) + return c.GetFsError(fs, err) + } + + for _, fileObj := range filesToRemove { + err = c.RemoveFile(fs, fileObj.fsPath, fileObj.virtualPath, fileObj.info) + if err != nil { + c.Log(logger.LevelError, "unable to remove dir tree, error removing file %q->%q: %v", + fileObj.virtualPath, fileObj.fsPath, err) + return err + } + } + + for _, dirObj := range orderDirsToRemove(fs, dirsToRemove) { + err = c.RemoveDir(dirObj.virtualPath) + if err != nil { + c.Log(logger.LevelDebug, "unable to remove dir tree, error removing directory %q->%q: %v", + dirObj.virtualPath, dirObj.fsPath, err) + return err + } + } + + return err +} + +// RemoveAll removes the specified path and any children it contains +func (c *BaseConnection) RemoveAll(virtualPath string) error { + fs, fsPath, err := c.GetFsAndResolvedPath(virtualPath) + if err != nil { + return err + } + + fi, err := fs.Lstat(fsPath) + if err != nil { + c.Log(logger.LevelDebug, "failed to remove path %q: stat error: %+v", fsPath, err) + return c.GetFsError(fs, err) + } + if fi.IsDir() && fi.Mode()&os.ModeSymlink == 0 { + return c.removeDirTree(fs, fsPath, virtualPath) + } + return c.RemoveFile(fs, fsPath, virtualPath, fi) +} + // Rename renames (moves) virtualSourcePath to virtualTargetPath func (c *BaseConnection) Rename(virtualSourcePath, virtualTargetPath string) error { if virtualSourcePath == virtualTargetPath { @@ -509,7 +635,7 @@ func (c *BaseConnection) Rename(virtualSourcePath, virtualTargetPath string) err initialSize = dstInfo.Size() } if !c.User.HasPerm(dataprovider.PermOverwrite, path.Dir(virtualTargetPath)) { - c.Log(logger.LevelDebug, "renaming %#v -> %#v is not allowed. Target exists but the user %#v"+ + c.Log(logger.LevelDebug, "renaming %q -> %q is not allowed. Target exists but the user %q"+ "has no overwrite permission", virtualSourcePath, virtualTargetPath, c.User.Username) return c.GetPermissionDeniedError() } @@ -824,11 +950,15 @@ func (c *BaseConnection) checkRecursiveRenameDirPermissions(fsSrc, fsDst vfs.Fs, if err != nil { return c.GetFsError(fsSrc, err) } + if walkedPath != sourcePath && vfs.HasImplicitAtomicUploads(fsSrc) { + c.Log(logger.LevelInfo, "cannot rename non empty directory %q on this filesystem", virtualSourcePath) + return c.GetOpUnsupportedError() + } dstPath := strings.Replace(walkedPath, sourcePath, targetPath, 1) virtualSrcPath := fsSrc.GetRelativePath(walkedPath) virtualDstPath := fsDst.GetRelativePath(dstPath) if !c.isRenamePermitted(fsSrc, fsDst, walkedPath, dstPath, virtualSrcPath, virtualDstPath, info) { - c.Log(logger.LevelInfo, "rename %#v -> %#v is not allowed, virtual destination path: %#v", + c.Log(logger.LevelInfo, "rename %q -> %q is not allowed, virtual destination path: %q", walkedPath, dstPath, virtualDstPath) return c.GetPermissionDeniedError() } @@ -866,7 +996,7 @@ func (c *BaseConnection) isRenamePermitted(fsSrc, fsDst vfs.Fs, fsSourcePath, fs virtualTargetPath string, fi os.FileInfo, ) bool { if !c.isSameResourceRename(virtualSourcePath, virtualTargetPath) { - c.Log(logger.LevelInfo, "rename %#v->%#v is not allowed: the paths must be on the same resource", + c.Log(logger.LevelInfo, "rename %#q->%q is not allowed: the paths must be on the same resource", virtualSourcePath, virtualTargetPath) return false } diff --git a/internal/common/connection_test.go b/internal/common/connection_test.go index 77c3fe87..dcfc1dd1 100644 --- a/internal/common/connection_test.go +++ b/internal/common/connection_test.go @@ -15,6 +15,7 @@ package common import ( + "errors" "os" "path" "path/filepath" @@ -33,11 +34,17 @@ import ( "github.com/drakkan/sftpgo/v2/internal/vfs" ) +var ( + errWalkDir = errors.New("err walk dir") + errWalkFile = errors.New("err walk file") +) + // MockOsFs mockable OsFs type MockOsFs struct { vfs.Fs hasVirtualFolders bool name string + err error } // Name returns the name for the Fs implementation @@ -61,11 +68,22 @@ func (fs *MockOsFs) Chtimes(name string, atime, mtime time.Time, isUploading boo return vfs.ErrVfsUnsupported } -func newMockOsFs(hasVirtualFolders bool, connectionID, rootDir, name string) vfs.Fs { +// Walk returns a duplicate path for testing +func (fs *MockOsFs) Walk(root string, walkFn filepath.WalkFunc) error { + if fs.err == errWalkDir { + walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck + return walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck + } + walkFn("fsfpath", vfs.NewFileInfo("fpath", false, 0, time.Now(), false), nil) //nolint:errcheck + return fs.err +} + +func newMockOsFs(hasVirtualFolders bool, connectionID, rootDir, name string, err error) vfs.Fs { return &MockOsFs{ Fs: vfs.NewOsFs(connectionID, rootDir, ""), name: name, hasVirtualFolders: hasVirtualFolders, + err: err, } } @@ -113,7 +131,7 @@ func TestSetStatMode(t *testing.T) { } user.Permissions = make(map[string][]string) user.Permissions["/"] = []string{dataprovider.PermAny} - fs := newMockOsFs(true, "", user.GetHomeDir(), "") + fs := newMockOsFs(true, "", user.GetHomeDir(), "", nil) conn := NewBaseConnection("", ProtocolWebDAV, "", "", user) err := conn.handleChmod(fs, fakePath, fakePath, nil) assert.NoError(t, err) @@ -148,6 +166,15 @@ func TestRecursiveRenameWalkError(t *testing.T) { filepath.Join(os.TempDir(), "/target"), "/source", "/target", vfs.NewFileInfo("source", true, 0, time.Now(), false)) assert.ErrorIs(t, err, os.ErrNotExist) + + fs = newMockOsFs(false, "mockID", filepath.Clean(os.TempDir()), "S3Fs", errWalkDir) + err = conn.checkRecursiveRenameDirPermissions(fs, fs, filepath.Join(os.TempDir(), "/source"), + filepath.Join(os.TempDir(), "/target"), "/source", "/target", + vfs.NewFileInfo("source", true, 0, time.Now(), false)) + if assert.Error(t, err) { + assert.Equal(t, err.Error(), conn.GetOpUnsupportedError().Error()) + } + conn.User.Permissions["/"] = []string{dataprovider.PermListItems, dataprovider.PermUpload, dataprovider.PermDownload, dataprovider.PermRenameFiles} // no dir rename permission, the quick check path returns permission error without walking @@ -441,7 +468,7 @@ func TestMaxWriteSize(t *testing.T) { assert.NoError(t, err) assert.Equal(t, int64(90), size) - fs = newMockOsFs(true, fs.ConnectionID(), user.GetHomeDir(), "") + fs = newMockOsFs(true, fs.ConnectionID(), user.GetHomeDir(), "", nil) size, err = conn.GetMaxWriteSize(quotaResult, true, 100, fs.IsUploadResumeSupported()) assert.EqualError(t, err, ErrOpUnsupported.Error()) assert.Equal(t, int64(0), size) @@ -519,3 +546,98 @@ func TestCheckParentDirsErrors(t *testing.T) { err = os.RemoveAll(filepath.Join(os.TempDir(), "sub-dir")) assert.NoError(t, err) } + +func TestRemoveDirTree(t *testing.T) { + user := dataprovider.User{ + BaseUser: sdk.BaseUser{ + HomeDir: filepath.Clean(os.TempDir()), + }, + } + user.Permissions = make(map[string][]string) + user.Permissions["/"] = []string{dataprovider.PermAny} + fs := vfs.NewOsFs("connID", user.HomeDir, "") + connection := NewBaseConnection(fs.ConnectionID(), ProtocolWebDAV, "", "", user) + + vpath := path.Join("adir", "missing") + p := filepath.Join(user.HomeDir, "adir", "missing") + err := connection.removeDirTree(fs, p, vpath) + if assert.Error(t, err) { + assert.True(t, fs.IsNotExist(err)) + } + + fs = newMockOsFs(false, "mockID", user.HomeDir, "", nil) + err = connection.removeDirTree(fs, p, vpath) + if assert.Error(t, err) { + assert.True(t, fs.IsNotExist(err), "unexpected error: %v", err) + } + + errFake := errors.New("fake err") + fs = newMockOsFs(false, "mockID", user.HomeDir, "", errFake) + err = connection.removeDirTree(fs, p, vpath) + if assert.Error(t, err) { + assert.EqualError(t, err, ErrGenericFailure.Error()) + } + + fs = newMockOsFs(true, "mockID", user.HomeDir, "", errWalkDir) + err = connection.removeDirTree(fs, p, vpath) + if assert.Error(t, err) { + assert.True(t, fs.IsPermission(err), "unexpected error: %v", err) + } + + fs = newMockOsFs(false, "mockID", user.HomeDir, "", errWalkFile) + err = connection.removeDirTree(fs, p, vpath) + if assert.Error(t, err) { + assert.EqualError(t, err, ErrGenericFailure.Error()) + } + + connection.User.Permissions["/"] = []string{dataprovider.PermListItems} + fs = newMockOsFs(false, "mockID", user.HomeDir, "", nil) + err = connection.removeDirTree(fs, p, vpath) + if assert.Error(t, err) { + assert.EqualError(t, err, ErrPermissionDenied.Error()) + } +} + +func TestOrderDirsToRemove(t *testing.T) { + fs := vfs.NewOsFs("id", os.TempDir(), "") + dirsToRemove := []objectToRemoveMapping{} + + orderedDirs := orderDirsToRemove(fs, dirsToRemove) + assert.Equal(t, len(dirsToRemove), len(orderedDirs)) + + dirsToRemove = []objectToRemoveMapping{ + { + fsPath: "dir1", + virtualPath: "", + }, + } + orderedDirs = orderDirsToRemove(fs, dirsToRemove) + assert.Equal(t, len(dirsToRemove), len(orderedDirs)) + + dirsToRemove = []objectToRemoveMapping{ + { + fsPath: "dir1", + virtualPath: "", + }, + { + fsPath: "dir12", + virtualPath: "", + }, + { + fsPath: filepath.Join("dir1", "a", "b"), + virtualPath: "", + }, + { + fsPath: filepath.Join("dir1", "a"), + virtualPath: "", + }, + } + + orderedDirs = orderDirsToRemove(fs, dirsToRemove) + if assert.Equal(t, len(dirsToRemove), len(orderedDirs)) { + assert.Equal(t, "dir12", orderedDirs[0].fsPath) + assert.Equal(t, filepath.Join("dir1", "a", "b"), orderedDirs[1].fsPath) + assert.Equal(t, filepath.Join("dir1", "a"), orderedDirs[2].fsPath) + assert.Equal(t, "dir1", orderedDirs[3].fsPath) + } +} diff --git a/internal/common/protocol_test.go b/internal/common/protocol_test.go index 129aab4a..5fb18aec 100644 --- a/internal/common/protocol_test.go +++ b/internal/common/protocol_test.go @@ -47,6 +47,7 @@ import ( "github.com/sftpgo/sdk" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/studio-b12/gowebdav" "golang.org/x/crypto/ssh" "github.com/drakkan/sftpgo/v2/internal/common" @@ -61,6 +62,7 @@ import ( "github.com/drakkan/sftpgo/v2/internal/smtp" "github.com/drakkan/sftpgo/v2/internal/util" "github.com/drakkan/sftpgo/v2/internal/vfs" + "github.com/drakkan/sftpgo/v2/internal/webdavd" ) const ( @@ -68,6 +70,7 @@ const ( httpProxyAddr = "127.0.0.1:7777" sftpServerAddr = "127.0.0.1:4022" smtpServerAddr = "127.0.0.1:2525" + webDavServerPort = 9191 defaultUsername = "test_common_sftp" defaultPassword = "test_password" defaultSFTPUsername = "test_common_sftpfs_user" @@ -145,6 +148,13 @@ func TestMain(m *testing.M) { httpdConf.Bindings[0].Port = 4080 httpdtest.SetBaseURL("http://127.0.0.1:4080") + webDavConf := config.GetWebDAVDConfig() + webDavConf.Bindings = []webdavd.Binding{ + { + Port: webDavServerPort, + }, + } + go func() { if err := sftpdConf.Initialize(configDir); err != nil { logger.ErrorToConsole("could not start SFTP server: %v", err) @@ -159,8 +169,16 @@ func TestMain(m *testing.M) { } }() + go func() { + if err := webDavConf.Initialize(configDir); err != nil { + logger.ErrorToConsole("could not start WebDAV server: %v", err) + os.Exit(1) + } + }() + waitTCPListening(sftpdConf.Bindings[0].GetAddress()) waitTCPListening(httpdConf.Bindings[0].GetAddress()) + waitTCPListening(webDavConf.Bindings[0].GetAddress()) go func() { // start a test HTTP server to receive action notifications @@ -315,6 +333,50 @@ func TestBaseConnection(t *testing.T) { assert.NoError(t, err) } +func TestRemoveAll(t *testing.T) { + u := getTestUser() + user, _, err := httpdtest.AddUser(u, http.StatusCreated) + assert.NoError(t, err) + + webDavClient := getWebDavClient(user) + err = webDavClient.RemoveAll("/") + if assert.Error(t, err) { + assert.True(t, gowebdav.IsErrCode(err, http.StatusForbidden)) + } + + testDir := "baseDir" + err = webDavClient.RemoveAll(testDir) + assert.NoError(t, err) + + conn, client, err := getSftpClient(user) + if assert.NoError(t, err) { + defer conn.Close() + defer client.Close() + + err = client.Mkdir(testDir) + assert.NoError(t, err) + err = writeSFTPFile(path.Join(testDir, testFileName), 1234, client) + assert.NoError(t, err) + + err = webDavClient.RemoveAll(path.Join(testDir, testFileName)) + assert.NoError(t, err) + _, err = client.Stat(path.Join(testDir, testFileName)) + assert.Error(t, err) + + err = writeSFTPFile(path.Join(testDir, testFileName), 1234, client) + assert.NoError(t, err) + err = webDavClient.RemoveAll(testDir) + assert.NoError(t, err) + _, err = client.Stat(testDir) + assert.Error(t, err) + } + + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + err = os.RemoveAll(user.GetHomeDir()) + assert.NoError(t, err) +} + func TestRelativeSymlinks(t *testing.T) { u := getTestUser() user, _, err := httpdtest.AddUser(u, http.StatusCreated) @@ -2951,6 +3013,8 @@ func TestResolvePathError(t *testing.T) { assert.Error(t, err) _, err = conn.DoStat(testPath, 0, false) assert.Error(t, err) + err = conn.RemoveAll(testPath) + assert.Error(t, err) err = conn.SetStat(testPath, &common.StatAttributes{ Atime: time.Now(), Mtime: time.Now(), @@ -6409,6 +6473,17 @@ func getSftpClient(user dataprovider.User) (*ssh.Client, *sftp.Client, error) { return conn, sftpClient, err } +func getWebDavClient(user dataprovider.User) *gowebdav.Client { + rootPath := fmt.Sprintf("http://localhost:%d/", webDavServerPort) + pwd := defaultPassword + if user.Password != "" { + pwd = user.Password + } + client := gowebdav.NewClient(rootPath, user.Username, pwd) + client.SetTimeout(10 * time.Second) + return client +} + func getTestUser() dataprovider.User { user := dataprovider.User{ BaseUser: sdk.BaseUser{ diff --git a/internal/common/transfer_test.go b/internal/common/transfer_test.go index 7e5a4961..b9e71383 100644 --- a/internal/common/transfer_test.go +++ b/internal/common/transfer_test.go @@ -62,7 +62,7 @@ func TestTransferUpdateQuota(t *testing.T) { assert.NoError(t, err) transfer.ErrTransfer = errFake - transfer.Fs = newMockOsFs(true, "", "", "S3Fs fake") + transfer.Fs = newMockOsFs(true, "", "", "S3Fs fake", nil) assert.False(t, transfer.updateQuota(1, 0)) } diff --git a/internal/httpd/api_http_user.go b/internal/httpd/api_http_user.go index 0901f993..d6faf9ca 100644 --- a/internal/httpd/api_http_user.go +++ b/internal/httpd/api_http_user.go @@ -119,12 +119,12 @@ func deleteUserDir(w http.ResponseWriter, r *http.Request) { defer common.Connections.Remove(connection.GetID()) name := connection.User.GetCleanedPath(r.URL.Query().Get("path")) - err = connection.RemoveDir(name) + err = connection.RemoveAll(name) if err != nil { - sendAPIResponse(w, r, err, fmt.Sprintf("Unable to delete directory %#v", name), getMappedStatusCode(err)) + sendAPIResponse(w, r, err, fmt.Sprintf("Unable to delete directory %q", name), getMappedStatusCode(err)) return } - sendAPIResponse(w, r, nil, fmt.Sprintf("Directory %#v deleted", name), http.StatusOK) + sendAPIResponse(w, r, nil, fmt.Sprintf("Directory %q deleted", name), http.StatusOK) } func getUserFile(w http.ResponseWriter, r *http.Request) { diff --git a/internal/webdavd/handler.go b/internal/webdavd/handler.go index 3865cd88..e90852f0 100644 --- a/internal/webdavd/handler.go +++ b/internal/webdavd/handler.go @@ -112,21 +112,7 @@ func (c *Connection) RemoveAll(ctx context.Context, name string) error { c.UpdateLastActivity() name = util.CleanPath(name) - fs, p, err := c.GetFsAndResolvedPath(name) - if err != nil { - return err - } - - var fi os.FileInfo - if fi, err = fs.Lstat(p); err != nil { - c.Log(logger.LevelDebug, "failed to remove file %#v: stat error: %+v", p, err) - return c.GetFsError(fs, err) - } - - if fi.IsDir() && fi.Mode()&os.ModeSymlink == 0 { - return c.removeDirTree(fs, p, name) - } - return c.RemoveFile(fs, p, name, fi) + return c.BaseConnection.RemoveAll(name) } // OpenFile opens the named file with specified flag. @@ -290,111 +276,3 @@ func (c *Connection) handleUploadToExistingFile(fs vfs.Fs, resolvedPath, filePat return newWebDavFile(baseTransfer, w, nil), nil } - -type objectMapping struct { - fsPath string - virtualPath string - info os.FileInfo -} - -func (c *Connection) removeDirTree(fs vfs.Fs, fsPath, virtualPath string) error { - var dirsToRemove []objectMapping - var filesToRemove []objectMapping - - err := fs.Walk(fsPath, func(walkedPath string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - obj := objectMapping{ - fsPath: walkedPath, - virtualPath: fs.GetRelativePath(walkedPath), - info: info, - } - if info.IsDir() { - err = c.IsRemoveDirAllowed(fs, obj.fsPath, obj.virtualPath) - isDuplicated := false - for _, d := range dirsToRemove { - if d.fsPath == obj.fsPath { - isDuplicated = true - break - } - } - if !isDuplicated { - dirsToRemove = append(dirsToRemove, obj) - } - } else { - err = c.IsRemoveFileAllowed(obj.virtualPath) - filesToRemove = append(filesToRemove, obj) - } - if err != nil { - c.Log(logger.LevelDebug, "unable to remove dir tree, object %#v->%#v cannot be removed: %v", - virtualPath, fsPath, err) - return err - } - - return nil - }) - if err != nil { - c.Log(logger.LevelError, "failed to remove dir tree %#v->%#v: error: %+v", virtualPath, fsPath, err) - return err - } - - for _, fileObj := range filesToRemove { - err = c.RemoveFile(fs, fileObj.fsPath, fileObj.virtualPath, fileObj.info) - if err != nil { - c.Log(logger.LevelDebug, "unable to remove dir tree, error removing file %#v->%#v: %v", - fileObj.virtualPath, fileObj.fsPath, err) - return err - } - } - - for _, dirObj := range c.orderDirsToRemove(fs, dirsToRemove) { - err = c.RemoveDir(dirObj.virtualPath) - if err != nil { - c.Log(logger.LevelDebug, "unable to remove dir tree, error removing directory %#v->%#v: %v", - dirObj.virtualPath, dirObj.fsPath, err) - return err - } - } - - return err -} - -// order directories so that the empty ones will be at slice start -func (c *Connection) orderDirsToRemove(fs vfs.Fs, dirsToRemove []objectMapping) []objectMapping { - orderedDirs := make([]objectMapping, 0, len(dirsToRemove)) - removedDirs := make([]string, 0, len(dirsToRemove)) - - pathSeparator := "/" - if vfs.IsLocalOsFs(fs) { - pathSeparator = string(os.PathSeparator) - } - - for len(orderedDirs) < len(dirsToRemove) { - for idx, d := range dirsToRemove { - if util.Contains(removedDirs, d.fsPath) { - continue - } - isEmpty := true - for idx1, d1 := range dirsToRemove { - if idx == idx1 { - continue - } - if util.Contains(removedDirs, d1.fsPath) { - continue - } - if strings.HasPrefix(d1.fsPath, d.fsPath+pathSeparator) { - isEmpty = false - break - } - } - if isEmpty { - orderedDirs = append(orderedDirs, d) - removedDirs = append(removedDirs, d.fsPath) - } - } - } - - return orderedDirs -} diff --git a/internal/webdavd/internal_test.go b/internal/webdavd/internal_test.go index ee479adc..f0e568d9 100644 --- a/internal/webdavd/internal_test.go +++ b/internal/webdavd/internal_test.go @@ -19,7 +19,6 @@ import ( "crypto/tls" "crypto/x509" "encoding/xml" - "errors" "fmt" "io" "net/http" @@ -272,11 +271,6 @@ xr5cb9VBRBtB9aOKVfuRhpatAfS2Pzm2Htae9lFn7slGPUmu2hkjDw== -----END RSA PRIVATE KEY-----` ) -var ( - errWalkDir = errors.New("err walk dir") - errWalkFile = errors.New("err walk file") -) - // MockOsFs mockable OsFs type MockOsFs struct { vfs.Fs @@ -315,86 +309,22 @@ func (fs *MockOsFs) Remove(name string, isDir bool) error { // Rename renames (moves) source to target func (fs *MockOsFs) Rename(source, target string) error { - if fs.err != nil { - return fs.err - } return os.Rename(source, target) } -// Walk returns a duplicate path for testing -func (fs *MockOsFs) Walk(root string, walkFn filepath.WalkFunc) error { - if fs.err == errWalkDir { - walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck - walkFn("fsdpath", vfs.NewFileInfo("dpath", true, 0, time.Now(), false), nil) //nolint:errcheck - return nil - } - walkFn("fsfpath", vfs.NewFileInfo("fpath", false, 0, time.Now(), false), nil) //nolint:errcheck - return fs.err -} - // GetMimeType returns the content type func (fs *MockOsFs) GetMimeType(name string) (string, error) { return "application/custom-mime", nil } -func newMockOsFs(err error, atomicUpload bool, connectionID, rootDir string, reader *pipeat.PipeReaderAt) vfs.Fs { +func newMockOsFs(atomicUpload bool, connectionID, rootDir string, reader *pipeat.PipeReaderAt) vfs.Fs { return &MockOsFs{ Fs: vfs.NewOsFs(connectionID, rootDir, ""), - err: err, isAtomicUploadSupported: atomicUpload, reader: reader, } } -func TestOrderDirsToRemove(t *testing.T) { - user := dataprovider.User{} - fs := vfs.NewOsFs("id", os.TempDir(), "") - connection := &Connection{ - BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, "", "", user), - request: nil, - } - dirsToRemove := []objectMapping{} - - orderedDirs := connection.orderDirsToRemove(fs, dirsToRemove) - assert.Equal(t, len(dirsToRemove), len(orderedDirs)) - - dirsToRemove = []objectMapping{ - { - fsPath: "dir1", - virtualPath: "", - }, - } - orderedDirs = connection.orderDirsToRemove(fs, dirsToRemove) - assert.Equal(t, len(dirsToRemove), len(orderedDirs)) - - dirsToRemove = []objectMapping{ - { - fsPath: "dir1", - virtualPath: "", - }, - { - fsPath: "dir12", - virtualPath: "", - }, - { - fsPath: filepath.Join("dir1", "a", "b"), - virtualPath: "", - }, - { - fsPath: filepath.Join("dir1", "a"), - virtualPath: "", - }, - } - - orderedDirs = connection.orderDirsToRemove(fs, dirsToRemove) - if assert.Equal(t, len(dirsToRemove), len(orderedDirs)) { - assert.Equal(t, "dir12", orderedDirs[0].fsPath) - assert.Equal(t, filepath.Join("dir1", "a", "b"), orderedDirs[1].fsPath) - assert.Equal(t, filepath.Join("dir1", "a"), orderedDirs[2].fsPath) - assert.Equal(t, "dir1", orderedDirs[3].fsPath) - } -} - func TestUserInvalidParams(t *testing.T) { u := &dataprovider.User{ BaseUser: sdk.BaseUser{ @@ -643,7 +573,7 @@ func TestFileAccessErrors(t *testing.T) { assert.ErrorIs(t, err, os.ErrNotExist) } - fs = newMockOsFs(nil, false, fs.ConnectionID(), user.HomeDir, nil) + fs = newMockOsFs(false, fs.ConnectionID(), user.HomeDir, nil) _, err = connection.handleUploadToExistingFile(fs, p, p, 0, path.Join("adir", missingPath)) if assert.Error(t, err) { assert.ErrorIs(t, err, os.ErrNotExist) @@ -706,59 +636,6 @@ func TestFileAccessErrors(t *testing.T) { } } -func TestRemoveDirTree(t *testing.T) { - user := dataprovider.User{ - BaseUser: sdk.BaseUser{ - HomeDir: filepath.Clean(os.TempDir()), - }, - } - user.Permissions = make(map[string][]string) - user.Permissions["/"] = []string{dataprovider.PermAny} - fs := vfs.NewOsFs("connID", user.HomeDir, "") - connection := &Connection{ - BaseConnection: common.NewBaseConnection(fs.ConnectionID(), common.ProtocolWebDAV, "", "", user), - } - - vpath := path.Join("adir", "missing") - p := filepath.Join(user.HomeDir, "adir", "missing") - err := connection.removeDirTree(fs, p, vpath) - if assert.Error(t, err) { - assert.True(t, fs.IsNotExist(err)) - } - - fs = newMockOsFs(nil, false, "mockID", user.HomeDir, nil) - err = connection.removeDirTree(fs, p, vpath) - if assert.Error(t, err) { - assert.True(t, fs.IsNotExist(err), "unexpected error: %v", err) - } - - errFake := errors.New("fake err") - fs = newMockOsFs(errFake, false, "mockID", user.HomeDir, nil) - err = connection.removeDirTree(fs, p, vpath) - if assert.Error(t, err) { - assert.EqualError(t, err, errFake.Error()) - } - - fs = newMockOsFs(errWalkDir, true, "mockID", user.HomeDir, nil) - err = connection.removeDirTree(fs, p, vpath) - if assert.Error(t, err) { - assert.True(t, fs.IsPermission(err), "unexpected error: %v", err) - } - - fs = newMockOsFs(errWalkFile, false, "mockID", user.HomeDir, nil) - err = connection.removeDirTree(fs, p, vpath) - if assert.Error(t, err) { - assert.EqualError(t, err, errWalkFile.Error()) - } - - connection.User.Permissions["/"] = []string{dataprovider.PermListItems} - fs = newMockOsFs(nil, false, "mockID", user.HomeDir, nil) - err = connection.removeDirTree(fs, p, vpath) - if assert.Error(t, err) { - assert.EqualError(t, err, common.ErrPermissionDenied.Error()) - } -} - func TestContentType(t *testing.T) { user := dataprovider.User{ BaseUser: sdk.BaseUser{ @@ -775,7 +652,7 @@ func TestContentType(t *testing.T) { ctx := context.Background() baseTransfer := common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFilePath, testFile, common.TransferDownload, 0, 0, 0, 0, false, fs, dataprovider.TransferQuota{}) - fs = newMockOsFs(nil, false, fs.ConnectionID(), user.GetHomeDir(), nil) + fs = newMockOsFs(false, fs.ConnectionID(), user.GetHomeDir(), nil) err := os.WriteFile(testFilePath, []byte(""), os.ModePerm) assert.NoError(t, err) davFile := newWebDavFile(baseTransfer, nil, nil) @@ -873,7 +750,7 @@ func TestTransferReadWriteErrors(t *testing.T) { r, w, err = pipeat.Pipe() assert.NoError(t, err) - mockFs := newMockOsFs(nil, false, fs.ConnectionID(), user.HomeDir, r) + mockFs := newMockOsFs(false, fs.ConnectionID(), user.HomeDir, r) baseTransfer = common.NewBaseTransfer(nil, connection.BaseConnection, nil, testFilePath, testFilePath, testFile, common.TransferDownload, 0, 0, 0, 0, false, mockFs, dataprovider.TransferQuota{}) davFile = newWebDavFile(baseTransfer, nil, nil) @@ -974,13 +851,13 @@ func TestTransferSeek(t *testing.T) { common.TransferDownload, 0, 0, 0, 0, false, fs, dataprovider.TransferQuota{AllowedTotalSize: 100}) davFile = newWebDavFile(baseTransfer, nil, nil) davFile.reader = f - davFile.Fs = newMockOsFs(nil, true, fs.ConnectionID(), user.GetHomeDir(), nil) + davFile.Fs = newMockOsFs(true, fs.ConnectionID(), user.GetHomeDir(), nil) res, err = davFile.Seek(2, io.SeekStart) assert.NoError(t, err) assert.Equal(t, int64(2), res) davFile = newWebDavFile(baseTransfer, nil, nil) - davFile.Fs = newMockOsFs(nil, true, fs.ConnectionID(), user.GetHomeDir(), nil) + davFile.Fs = newMockOsFs(true, fs.ConnectionID(), user.GetHomeDir(), nil) res, err = davFile.Seek(2, io.SeekEnd) assert.NoError(t, err) assert.Equal(t, int64(5), res) @@ -989,7 +866,7 @@ func TestTransferSeek(t *testing.T) { common.TransferDownload, 0, 0, 0, 0, false, fs, dataprovider.TransferQuota{AllowedTotalSize: 100}) davFile = newWebDavFile(baseTransfer, nil, nil) - davFile.Fs = newMockOsFs(nil, true, fs.ConnectionID(), user.GetHomeDir(), nil) + davFile.Fs = newMockOsFs(true, fs.ConnectionID(), user.GetHomeDir(), nil) res, err = davFile.Seek(2, io.SeekEnd) assert.True(t, fs.IsNotExist(err)) assert.Equal(t, int64(0), res) diff --git a/templates/webclient/files.html b/templates/webclient/files.html index 0f7835d2..4bb5cef5 100644 --- a/templates/webclient/files.html +++ b/templates/webclient/files.html @@ -594,8 +594,10 @@ along with this program. If not, see . var itemType = getTypeFromMeta(selected); var itemName = getNameFromMeta(selected); var path; + var reqTimeout = 15000; if (itemType == "1"){ path = '{{.DirsURL}}'; + reqTimeout = 90000 } else { path = '{{.FilesURL}}'; } @@ -606,7 +608,7 @@ along with this program. If not, see . type: 'DELETE', dataType: 'json', headers: { 'X-CSRF-TOKEN': '{{.CSRFToken}}' }, - timeout: 60000, + timeout: reqTimeout, success: function (result) { index++; success++;