update deps

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2023-12-14 16:06:20 +01:00
parent 8e86782d85
commit be2e24e63d
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
16 changed files with 606 additions and 2915 deletions

View file

@ -11,11 +11,11 @@ jobs:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
go: [1.19] go: ['1.20']
os: [ubuntu-latest, macos-latest] os: [ubuntu-latest, macos-latest]
upload-coverage: [true] upload-coverage: [true]
include: include:
- go: 1.19 - go: '1.20'
os: windows-latest os: windows-latest
upload-coverage: false upload-coverage: false
@ -232,7 +232,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: 1.19 go-version: '1.20'
- name: Build - name: Build
run: | run: |
@ -252,7 +252,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: 1.19 go-version: '1.20'
- name: Build - name: Build
run: | run: |
@ -326,7 +326,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: 1.19 go-version: '1.20'
- name: Build - name: Build
run: | run: |
@ -438,7 +438,7 @@ jobs:
echo 'apt-get install -q -y curl gcc' >> build.sh echo 'apt-get install -q -y curl gcc' >> build.sh
if [ ${{ matrix.go }} == 'latest' ] if [ ${{ matrix.go }} == 'latest' ]
then then
echo 'GO_VERSION=$(curl -L https://go.dev/VERSION?m=text)' >> build.sh echo 'GO_VERSION=$(curl -L https://go.dev/VERSION?m=text | head -n 1)' >> build.sh
else else
echo 'GO_VERSION=${{ matrix.go }}' >> build.sh echo 'GO_VERSION=${{ matrix.go }}' >> build.sh
fi fi
@ -481,7 +481,7 @@ jobs:
apt-get install -q -y curl gcc apt-get install -q -y curl gcc
if [ ${{ matrix.go }} == 'latest' ] if [ ${{ matrix.go }} == 'latest' ]
then then
GO_VERSION=$(curl -L https://go.dev/VERSION?m=text) GO_VERSION=$(curl -L https://go.dev/VERSION?m=text | head -n 1)
else else
GO_VERSION=${{ matrix.go }} GO_VERSION=${{ matrix.go }}
fi fi
@ -546,7 +546,7 @@ jobs:
- name: Set up Go - name: Set up Go
uses: actions/setup-go@v3 uses: actions/setup-go@v3
with: with:
go-version: 1.19 go-version: '1.19'
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Run golangci-lint - name: Run golangci-lint
uses: golangci/golangci-lint-action@v3 uses: golangci/golangci-lint-action@v3

View file

@ -5,7 +5,7 @@ on:
# - cron: '0 4 * * *' # everyday at 4:00 AM UTC # - cron: '0 4 * * *' # everyday at 4:00 AM UTC
push: push:
branches: branches:
- 2.4.x - main
tags: tags:
- v* - v*
pull_request: pull_request:

View file

@ -5,7 +5,7 @@ on:
tags: 'v*' tags: 'v*'
env: env:
GO_VERSION: 1.19.8 GO_VERSION: 1.20.12
jobs: jobs:
prepare-sources-with-deps: prepare-sources-with-deps:

234
go.mod
View file

@ -3,166 +3,182 @@ module github.com/drakkan/sftpgo/v2
go 1.19 go 1.19
require ( require (
cloud.google.com/go/storage v1.30.1 cloud.google.com/go/storage v1.35.1
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.5.0 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5 github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736 github.com/alexedwards/argon2id v1.0.0
github.com/aws/aws-sdk-go-v2 v1.17.8 github.com/aws/aws-sdk-go-v2 v1.24.0
github.com/aws/aws-sdk-go-v2/config v1.18.20 github.com/aws/aws-sdk-go-v2/config v1.26.1
github.com/aws/aws-sdk-go-v2/credentials v1.13.19 github.com/aws/aws-sdk-go-v2/credentials v1.16.12
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.2 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.61 github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.8 github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.19.5
github.com/aws/aws-sdk-go-v2/service/s3 v1.31.2 github.com/aws/aws-sdk-go-v2/service/s3 v1.47.5
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.2 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.25.5
github.com/aws/aws-sdk-go-v2/service/sts v1.18.8 github.com/aws/aws-sdk-go-v2/service/sts v1.26.5
github.com/cockroachdb/cockroach-go/v2 v2.3.3 github.com/cockroachdb/cockroach-go/v2 v2.3.5
github.com/coreos/go-oidc/v3 v3.5.0 github.com/coreos/go-oidc/v3 v3.9.0
github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8 github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8
github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001
github.com/fclairamb/ftpserverlib v0.21.0 github.com/fclairamb/ftpserverlib v0.22.0
github.com/fclairamb/go-log v0.4.1 github.com/fclairamb/go-log v0.4.1
github.com/go-acme/lego/v4 v4.10.2 github.com/go-acme/lego/v4 v4.14.2
github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/chi/v5 v5.0.10
github.com/go-chi/jwtauth/v5 v5.1.0 github.com/go-chi/jwtauth/v5 v5.3.0
github.com/go-chi/render v1.0.2 github.com/go-chi/render v1.0.3
github.com/go-sql-driver/mysql v1.7.0 github.com/go-sql-driver/mysql v1.7.1
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.3.0 github.com/google/uuid v1.5.0
github.com/grandcat/zeroconf v1.0.0 github.com/grandcat/zeroconf v1.0.0
github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-hclog v1.6.2
github.com/hashicorp/go-plugin v1.4.10-0.20230321181155-4b35dc2fedaa github.com/hashicorp/go-plugin v1.6.0
github.com/hashicorp/go-retryablehttp v0.7.2 github.com/hashicorp/go-retryablehttp v0.7.5
github.com/jackc/pgx/v5 v5.3.2-0.20230324225134-e9d64ec29d90 github.com/jackc/pgx/v5 v5.4.3
github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126 github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126
github.com/klauspost/compress v1.16.4 github.com/klauspost/compress v1.17.4
github.com/lestrrat-go/jwx/v2 v2.0.9 github.com/lestrrat-go/jwx/v2 v2.0.18
github.com/lithammer/shortuuid/v3 v3.0.7 github.com/lithammer/shortuuid/v3 v3.0.7
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.18
github.com/mhale/smtpd v0.8.0 github.com/mhale/smtpd v0.8.1
github.com/minio/sio v0.3.1 github.com/minio/sio v0.3.1
github.com/otiai10/copy v1.10.0 github.com/otiai10/copy v1.14.0
github.com/pires/go-proxyproto v0.7.0 github.com/pires/go-proxyproto v0.7.0
github.com/pkg/sftp v1.13.6-0.20230213180117-971c283182b6 github.com/pkg/sftp v1.13.6
github.com/pquerna/otp v1.4.0 github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.14.0 github.com/prometheus/client_golang v1.17.0
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/rs/cors v1.8.3 github.com/rs/cors v1.10.1
github.com/rs/xid v1.4.0 github.com/rs/xid v1.5.0
github.com/rs/zerolog v1.29.0 github.com/rs/zerolog v1.31.0
github.com/sftpgo/sdk v0.1.2 github.com/sftpgo/sdk v0.0.0-20231214102927-0493fcf3bc52
github.com/shirou/gopsutil/v3 v3.23.3 github.com/shirou/gopsutil/v3 v3.23.11
github.com/spf13/afero v1.9.5 github.com/spf13/afero v1.11.0
github.com/spf13/cobra v1.7.0 github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.15.0 github.com/spf13/viper v1.18.1
github.com/stretchr/testify v1.8.2 github.com/stretchr/testify v1.8.4
github.com/studio-b12/gowebdav v0.0.0-20230203202212-3282f94193f2 github.com/studio-b12/gowebdav v0.9.0
github.com/subosito/gotenv v1.4.2 github.com/subosito/gotenv v1.6.0
github.com/unrolled/secure v1.13.0 github.com/unrolled/secure v1.13.0
github.com/wagslane/go-password-validator v0.3.0 github.com/wagslane/go-password-validator v0.3.0
github.com/xhit/go-simple-mail/v2 v2.13.0 github.com/xhit/go-simple-mail/v2 v2.16.0
github.com/yl2chen/cidranger v1.0.3-0.20210928021809-d1cb2c52f37a github.com/yl2chen/cidranger v1.0.3-0.20210928021809-d1cb2c52f37a
go.etcd.io/bbolt v1.3.7 go.etcd.io/bbolt v1.3.8
go.uber.org/automaxprocs v1.5.2 go.uber.org/automaxprocs v1.5.3
gocloud.dev v0.29.0 gocloud.dev v0.35.0
golang.org/x/crypto v0.7.0 golang.org/x/crypto v0.16.0
golang.org/x/net v0.9.0 golang.org/x/net v0.19.0
golang.org/x/oauth2 v0.7.0 golang.org/x/oauth2 v0.15.0
golang.org/x/sys v0.7.0 golang.org/x/sys v0.15.0
golang.org/x/time v0.3.0 golang.org/x/time v0.5.0
google.golang.org/api v0.116.0 google.golang.org/api v0.154.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
) )
require ( require (
cloud.google.com/go v0.110.0 // indirect cloud.google.com/go v0.111.0 // indirect
cloud.google.com/go/compute v1.19.0 // indirect cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.0.0 // indirect cloud.google.com/go/iam v1.1.5 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect
github.com/ajg/form v1.5.1 // indirect github.com/ajg/form v1.5.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.33 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.9 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.16.9 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.7 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.18.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.7 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 // indirect
github.com/aws/smithy-go v1.13.5 // indirect github.com/aws/smithy-go v1.19.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect github.com/boombuler/barcode v1.0.1 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.2.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/fatih/color v1.15.0 // indirect github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-jose/go-jose/v3 v3.0.1 // indirect
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-test/deep v1.1.0 // indirect github.com/go-test/deep v1.1.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.8.0 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect github.com/hashicorp/yamux v0.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/kr/fs v0.1.0 // indirect github.com/kr/fs v0.1.0 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/miekg/dns v1.1.53 // indirect github.com/miekg/dns v1.1.57 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/oklog/run v1.1.0 // indirect github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.0.7 // indirect github.com/pelletier/go-toml/v2 v2.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/common v0.45.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shoenig/go-m1cpu v0.1.5 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/spf13/cast v1.5.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/segmentio/asm v1.2.0 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect github.com/tklauser/numcpus v0.7.0 // indirect
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
golang.org/x/mod v0.10.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect
golang.org/x/text v0.9.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
golang.org/x/tools v0.8.0 // indirect go.opentelemetry.io/otel v1.21.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect go.opentelemetry.io/otel/metric v1.21.0 // indirect
google.golang.org/appengine v1.6.7 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect
google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd // indirect go.uber.org/multierr v1.11.0 // indirect
google.golang.org/grpc v1.54.0 // indirect golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb // indirect
google.golang.org/protobuf v1.30.0 // indirect golang.org/x/mod v0.14.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.16.1 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/grpc v1.60.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )
@ -170,5 +186,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
github.com/robfig/cron/v3 => github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0 github.com/robfig/cron/v3 => github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20230106095953-5417b4dfde62 golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20231109074321-cb261f488895
) )

3009
go.sum

File diff suppressed because it is too large Load diff

View file

@ -219,7 +219,7 @@ func getUsersInGroupsQuery(numArgs int) string {
} else { } else {
sb.WriteString("('')") sb.WriteString("('')")
} }
return fmt.Sprintf(`SELECT username FROM %s WHERE id IN (SELECT user_id from %s WHERE group_id IN (SELECT id FROM %s WHERE name IN (%s)))`, return fmt.Sprintf(`SELECT username FROM %s WHERE id IN (SELECT user_id from %s WHERE group_id IN (SELECT id FROM %s WHERE name IN %s))`,
sqlTableUsers, sqlTableUsersGroupsMapping, getSQLQuotedName(sqlTableGroups), sb.String()) sqlTableUsers, sqlTableUsersGroupsMapping, getSQLQuotedName(sqlTableGroups), sb.String())
} }

View file

@ -1784,6 +1784,9 @@ func (u *User) mergeVirtualFolders(group Group, groupType int, replacer *strings
} }
func (u *User) mergePermissions(group Group, groupType int, replacer *strings.Replacer) { func (u *User) mergePermissions(group Group, groupType int, replacer *strings.Replacer) {
if u.Permissions == nil {
u.Permissions = make(map[string][]string)
}
for k, v := range group.UserSettings.Permissions { for k, v := range group.UserSettings.Permissions {
if k == "/" { if k == "/" {
if groupType == sdk.GroupTypePrimary { if groupType == sdk.GroupTypePrimary {

View file

@ -1975,6 +1975,13 @@ func TestLoadHostKeys(t *testing.T) {
c.HostKeys = []string{nonDefaultKeyName, rsaKeyName, ecdsaKeyName, ed25519KeyName} c.HostKeys = []string{nonDefaultKeyName, rsaKeyName, ecdsaKeyName, ed25519KeyName}
err = c.checkAndLoadHostKeys(configDir, serverConfig) err = c.checkAndLoadHostKeys(configDir, serverConfig)
assert.Error(t, err) assert.Error(t, err)
c.HostKeyAlgorithms = []string{ssh.KeyAlgoRSASHA256}
c.HostKeys = []string{ecdsaKeyName}
err = c.checkAndLoadHostKeys(configDir, serverConfig)
assert.Error(t, err)
c.HostKeyAlgorithms = preferredHostKeyAlgos
err = c.checkAndLoadHostKeys(configDir, serverConfig)
assert.NoError(t, err)
assert.FileExists(t, rsaKeyName) assert.FileExists(t, rsaKeyName)
assert.FileExists(t, ecdsaKeyName) assert.FileExists(t, ecdsaKeyName)
assert.FileExists(t, ed25519KeyName) assert.FileExists(t, ed25519KeyName)

View file

@ -47,6 +47,8 @@ const (
defaultPrivateECDSAKeyName = "id_ecdsa" defaultPrivateECDSAKeyName = "id_ecdsa"
defaultPrivateEd25519KeyName = "id_ed25519" defaultPrivateEd25519KeyName = "id_ed25519"
sourceAddressCriticalOption = "source-address" sourceAddressCriticalOption = "source-address"
kexDHGroupExchangeSHA1 = "diffie-hellman-group-exchange-sha1"
kexDHGroupExchangeSHA256 = "diffie-hellman-group-exchange-sha256"
) )
var ( var (
@ -61,11 +63,8 @@ var (
ssh.KeyAlgoED25519, ssh.KeyAlgoED25519,
} }
preferredHostKeyAlgos = []string{ preferredHostKeyAlgos = []string{
ssh.CertAlgoRSASHA512v01, ssh.CertAlgoRSASHA256v01, ssh.KeyAlgoRSASHA256, ssh.KeyAlgoRSASHA512,
ssh.CertAlgoECDSA256v01,
ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01, ssh.CertAlgoED25519v01,
ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521, ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521,
ssh.KeyAlgoRSASHA512, ssh.KeyAlgoRSASHA256,
ssh.KeyAlgoED25519, ssh.KeyAlgoED25519,
} }
supportedKexAlgos = []string{ supportedKexAlgos = []string{
@ -75,6 +74,11 @@ var (
"diffie-hellman-group18-sha512", "diffie-hellman-group14-sha1", "diffie-hellman-group18-sha512", "diffie-hellman-group14-sha1",
"diffie-hellman-group1-sha1", "diffie-hellman-group1-sha1",
} }
preferredKexAlgos = []string{
"curve25519-sha256", "curve25519-sha256@libssh.org",
"ecdh-sha2-nistp256", "ecdh-sha2-nistp384", "ecdh-sha2-nistp521",
"diffie-hellman-group14-sha256",
}
supportedCiphers = []string{ supportedCiphers = []string{
"aes128-gcm@openssh.com", "aes256-gcm@openssh.com", "aes128-gcm@openssh.com", "aes256-gcm@openssh.com",
"chacha20-poly1305@openssh.com", "chacha20-poly1305@openssh.com",
@ -83,11 +87,19 @@ var (
"3des-cbc", "3des-cbc",
"arcfour", "arcfour128", "arcfour256", "arcfour", "arcfour128", "arcfour256",
} }
preferredCiphers = []string{
"aes128-gcm@openssh.com", "aes256-gcm@openssh.com",
"chacha20-poly1305@openssh.com",
"aes128-ctr", "aes192-ctr", "aes256-ctr",
}
supportedMACs = []string{ supportedMACs = []string{
"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256",
"hmac-sha2-512-etm@openssh.com", "hmac-sha2-512", "hmac-sha2-512-etm@openssh.com", "hmac-sha2-512",
"hmac-sha1", "hmac-sha1-96", "hmac-sha1", "hmac-sha1-96",
} }
preferredMACs = []string{
"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256",
}
revokedCertManager = revokedCertificates{ revokedCertManager = revokedCertificates{
certs: map[string]bool{}, certs: map[string]bool{},
@ -315,15 +327,6 @@ func (c *Configuration) Initialize(configDir string) error {
return common.ErrNoBinding return common.ErrNoBinding
} }
if err := c.checkAndLoadHostKeys(configDir, serverConfig); err != nil {
serviceStatus.HostKeys = nil
return err
}
if err := c.initializeCertChecker(configDir); err != nil {
return err
}
if err := c.loadModuli(configDir); err != nil { if err := c.loadModuli(configDir); err != nil {
return err return err
} }
@ -333,6 +336,14 @@ func (c *Configuration) Initialize(configDir string) error {
if err := c.configureSecurityOptions(serverConfig); err != nil { if err := c.configureSecurityOptions(serverConfig); err != nil {
return err return err
} }
if err := c.checkAndLoadHostKeys(configDir, serverConfig); err != nil {
serviceStatus.HostKeys = nil
return err
}
if err := c.initializeCertChecker(configDir); err != nil {
return err
}
c.configureKeyboardInteractiveAuth(serverConfig) c.configureKeyboardInteractiveAuth(serverConfig)
c.configureLoginBanner(serverConfig, configDir) c.configureLoginBanner(serverConfig, configDir)
c.checkSSHCommands() c.checkSSHCommands()
@ -419,35 +430,43 @@ func (c *Configuration) configureSecurityOptions(serverConfig *ssh.ServerConfig)
return fmt.Errorf("unsupported host key algorithm %#v", hostKeyAlgo) return fmt.Errorf("unsupported host key algorithm %#v", hostKeyAlgo)
} }
} }
serverConfig.HostKeyAlgorithms = c.HostKeyAlgorithms
if len(c.KexAlgorithms) > 0 { if len(c.KexAlgorithms) == 0 {
c.KexAlgorithms = preferredKexAlgos
} else {
c.KexAlgorithms = util.RemoveDuplicates(c.KexAlgorithms, true) c.KexAlgorithms = util.RemoveDuplicates(c.KexAlgorithms, true)
for _, kex := range c.KexAlgorithms {
if !util.Contains(supportedKexAlgos, kex) {
return fmt.Errorf("unsupported key-exchange algorithm %#v", kex)
}
}
serverConfig.KeyExchanges = c.KexAlgorithms
} }
if len(c.Ciphers) > 0 { for _, kex := range c.KexAlgorithms {
if !util.Contains(supportedKexAlgos, kex) {
return fmt.Errorf("unsupported key-exchange algorithm %q", kex)
}
}
serverConfig.KeyExchanges = c.KexAlgorithms
if len(c.Ciphers) == 0 {
c.Ciphers = preferredCiphers
} else {
c.Ciphers = util.RemoveDuplicates(c.Ciphers, true) c.Ciphers = util.RemoveDuplicates(c.Ciphers, true)
for _, cipher := range c.Ciphers {
if !util.Contains(supportedCiphers, cipher) {
return fmt.Errorf("unsupported cipher %#v", cipher)
}
}
serverConfig.Ciphers = c.Ciphers
} }
if len(c.MACs) > 0 { for _, cipher := range c.Ciphers {
if !util.Contains(supportedCiphers, cipher) {
return fmt.Errorf("unsupported cipher %#v", cipher)
}
}
serverConfig.Ciphers = c.Ciphers
if len(c.MACs) == 0 {
c.MACs = preferredMACs
} else {
c.MACs = util.RemoveDuplicates(c.MACs, true) c.MACs = util.RemoveDuplicates(c.MACs, true)
for _, mac := range c.MACs {
if !util.Contains(supportedMACs, mac) {
return fmt.Errorf("unsupported MAC algorithm %#v", mac)
}
}
serverConfig.MACs = c.MACs
} }
for _, mac := range c.MACs {
if !util.Contains(supportedMACs, mac) {
return fmt.Errorf("unsupported MAC algorithm %#v", mac)
}
}
serverConfig.MACs = c.MACs
return nil return nil
} }
@ -876,8 +895,9 @@ func (c *Configuration) checkHostKeyAutoGeneration(configDir string) error {
} }
func (c *Configuration) loadModuli(configDir string) error { func (c *Configuration) loadModuli(configDir string) error {
supportedKexAlgos = util.Remove(supportedKexAlgos, "diffie-hellman-group-exchange-sha1") supportedKexAlgos = util.Remove(supportedKexAlgos, kexDHGroupExchangeSHA1)
supportedKexAlgos = util.Remove(supportedKexAlgos, "diffie-hellman-group-exchange-sha256") supportedKexAlgos = util.Remove(supportedKexAlgos, kexDHGroupExchangeSHA256)
preferredKexAlgos = util.Remove(preferredKexAlgos, kexDHGroupExchangeSHA256)
for _, m := range c.Moduli { for _, m := range c.Moduli {
m = strings.TrimSpace(m) m = strings.TrimSpace(m)
if !util.IsFileInputValid(m) { if !util.IsFileInputValid(m) {
@ -892,12 +912,29 @@ func (c *Configuration) loadModuli(configDir string) error {
if err := ssh.ParseModuli(m); err != nil { if err := ssh.ParseModuli(m); err != nil {
return err return err
} }
supportedKexAlgos = append(supportedKexAlgos, "diffie-hellman-group-exchange-sha1", if !util.Contains(supportedKexAlgos, kexDHGroupExchangeSHA1) {
"diffie-hellman-group-exchange-sha256") supportedKexAlgos = append(supportedKexAlgos, kexDHGroupExchangeSHA1)
}
if !util.Contains(supportedKexAlgos, kexDHGroupExchangeSHA256) {
supportedKexAlgos = append(supportedKexAlgos, kexDHGroupExchangeSHA256)
}
if !util.Contains(preferredKexAlgos, kexDHGroupExchangeSHA256) {
preferredKexAlgos = append(preferredKexAlgos, kexDHGroupExchangeSHA256)
}
} }
return nil return nil
} }
func (c *Configuration) getHostKeyAlgorithms(keyFormat string) []string {
var algos []string
for _, algo := range algorithmsForKeyFormat(keyFormat) {
if util.Contains(c.HostKeyAlgorithms, algo) {
algos = append(algos, algo)
}
}
return algos
}
// If no host keys are defined we try to use or generate the default ones. // If no host keys are defined we try to use or generate the default ones.
func (c *Configuration) checkAndLoadHostKeys(configDir string, serverConfig *ssh.ServerConfig) error { func (c *Configuration) checkAndLoadHostKeys(configDir string, serverConfig *ssh.ServerConfig) error {
if err := c.checkHostKeyAutoGeneration(configDir); err != nil { if err := c.checkHostKeyAutoGeneration(configDir); err != nil {
@ -932,22 +969,45 @@ func (c *Configuration) checkAndLoadHostKeys(configDir string, serverConfig *ssh
k := HostKey{ k := HostKey{
Path: hostKey, Path: hostKey,
Fingerprint: ssh.FingerprintSHA256(private.PublicKey()), Fingerprint: ssh.FingerprintSHA256(private.PublicKey()),
Algorithms: c.getHostKeyAlgorithms(private.PublicKey().Type()),
}
mas, err := ssh.NewSignerWithAlgorithms(private.(ssh.AlgorithmSigner), k.Algorithms)
if err != nil {
logger.Warn(logSender, "", "could not create signer for key %q with algorithms %+v: %v", k.Path, k.Algorithms, err)
logger.WarnToConsole("could not create signer for key %q with algorithms %+v: %v", k.Path, k.Algorithms, err)
continue
} }
serviceStatus.HostKeys = append(serviceStatus.HostKeys, k) serviceStatus.HostKeys = append(serviceStatus.HostKeys, k)
logger.Info(logSender, "", "Host key %#v loaded, type %#v, fingerprint %#v", hostKey, logger.Info(logSender, "", "Host key %q loaded, type %q, fingerprint %q, algorithms %+v", hostKey,
private.PublicKey().Type(), k.Fingerprint) private.PublicKey().Type(), k.Fingerprint, k.Algorithms)
// Add private key to the server configuration. // Add private key to the server configuration.
serverConfig.AddHostKey(private) serverConfig.AddHostKey(mas)
for _, cert := range hostCertificates { for _, cert := range hostCertificates {
signer, err := ssh.NewCertSigner(cert, private) signer, err := ssh.NewCertSigner(cert.Certificate, mas)
if err == nil { if err == nil {
var algos []string
for _, algo := range algorithmsForKeyFormat(signer.PublicKey().Type()) {
if underlyingAlgo, ok := certKeyAlgoNames[algo]; ok {
if util.Contains(mas.Algorithms(), underlyingAlgo) {
algos = append(algos, algo)
}
}
}
serviceStatus.HostKeys = append(serviceStatus.HostKeys, HostKey{
Path: cert.Path,
Fingerprint: ssh.FingerprintSHA256(signer.PublicKey()),
Algorithms: algos,
})
serverConfig.AddHostKey(signer) serverConfig.AddHostKey(signer)
logger.Info(logSender, "", "Host certificate loaded for host key %#v, fingerprint %#v", logger.Info(logSender, "", "Host certificate loaded for host key %q, fingerprint %q, algorithms %+v",
hostKey, ssh.FingerprintSHA256(signer.PublicKey())) hostKey, ssh.FingerprintSHA256(signer.PublicKey()), algos)
} }
} }
} }
if len(serviceStatus.HostKeys) == 0 {
return errors.New("ssh: server has no host keys")
}
var fp []string var fp []string
for idx := range serviceStatus.HostKeys { for idx := range serviceStatus.HostKeys {
h := &serviceStatus.HostKeys[idx] h := &serviceStatus.HostKeys[idx]
@ -957,8 +1017,8 @@ func (c *Configuration) checkAndLoadHostKeys(configDir string, serverConfig *ssh
return nil return nil
} }
func (c *Configuration) loadHostCertificates(configDir string) ([]*ssh.Certificate, error) { func (c *Configuration) loadHostCertificates(configDir string) ([]hostCertificate, error) {
var certs []*ssh.Certificate var certs []hostCertificate
for _, certPath := range c.HostCertificates { for _, certPath := range c.HostCertificates {
certPath = strings.TrimSpace(certPath) certPath = strings.TrimSpace(certPath)
if !util.IsFileInputValid(certPath) { if !util.IsFileInputValid(certPath) {
@ -984,7 +1044,10 @@ func (c *Configuration) loadHostCertificates(configDir string) ([]*ssh.Certifica
if cert.CertType != ssh.HostCert { if cert.CertType != ssh.HostCert {
return nil, fmt.Errorf("the file %#v is not an host certificate", certPath) return nil, fmt.Errorf("the file %#v is not an host certificate", certPath)
} }
certs = append(certs, cert) certs = append(certs, hostCertificate{
Path: certPath,
Certificate: cert,
})
} }
return certs, nil return certs, nil
} }
@ -1218,3 +1281,14 @@ func (r *revokedCertificates) isRevoked(fp string) bool {
func Reload() error { func Reload() error {
return revokedCertManager.load() return revokedCertManager.load()
} }
func algorithmsForKeyFormat(keyFormat string) []string {
switch keyFormat {
case ssh.KeyAlgoRSA:
return []string{ssh.KeyAlgoRSASHA256, ssh.KeyAlgoRSASHA512, ssh.KeyAlgoRSA}
case ssh.CertAlgoRSAv01:
return []string{ssh.CertAlgoRSASHA256v01, ssh.CertAlgoRSASHA512v01, ssh.CertAlgoRSAv01}
default:
return []string{keyFormat}
}
}

View file

@ -20,6 +20,8 @@ package sftpd
import ( import (
"strings" "strings"
"time" "time"
"golang.org/x/crypto/ssh"
) )
const ( const (
@ -34,6 +36,18 @@ var (
sshHashCommands = []string{"md5sum", "sha1sum", "sha256sum", "sha384sum", "sha512sum"} sshHashCommands = []string{"md5sum", "sha1sum", "sha256sum", "sha384sum", "sha512sum"}
systemCommands = []string{"git-receive-pack", "git-upload-pack", "git-upload-archive", "rsync"} systemCommands = []string{"git-receive-pack", "git-upload-pack", "git-upload-archive", "rsync"}
serviceStatus ServiceStatus serviceStatus ServiceStatus
certKeyAlgoNames = map[string]string{
ssh.CertAlgoRSAv01: ssh.KeyAlgoRSA,
ssh.CertAlgoRSASHA256v01: ssh.KeyAlgoRSASHA256,
ssh.CertAlgoRSASHA512v01: ssh.KeyAlgoRSASHA512,
ssh.CertAlgoDSAv01: ssh.KeyAlgoDSA,
ssh.CertAlgoECDSA256v01: ssh.KeyAlgoECDSA256,
ssh.CertAlgoECDSA384v01: ssh.KeyAlgoECDSA384,
ssh.CertAlgoECDSA521v01: ssh.KeyAlgoECDSA521,
ssh.CertAlgoSKECDSA256v01: ssh.KeyAlgoSKECDSA256,
ssh.CertAlgoED25519v01: ssh.KeyAlgoED25519,
ssh.CertAlgoSKED25519v01: ssh.KeyAlgoSKED25519,
}
) )
type sshSubsystemExitStatus struct { type sshSubsystemExitStatus struct {
@ -44,10 +58,21 @@ type sshSubsystemExecMsg struct {
Command string Command string
} }
type hostCertificate struct {
Certificate *ssh.Certificate
Path string
}
// HostKey defines the details for a used host key // HostKey defines the details for a used host key
type HostKey struct { type HostKey struct {
Path string `json:"path"` Path string `json:"path"`
Fingerprint string `json:"fingerprint"` Fingerprint string `json:"fingerprint"`
Algorithms []string `json:"algorithms"`
}
// GetAlgosAsString returns the host key algorithms as comma separated string
func (h *HostKey) GetAlgosAsString() string {
return strings.Join(h.Algorithms, ", ")
} }
// ServiceStatus defines the service status // ServiceStatus defines the service status

View file

@ -429,11 +429,13 @@ func TestInitialization(t *testing.T) {
if assert.Error(t, err) { if assert.Error(t, err) {
assert.Contains(t, err.Error(), "unsupported MAC algorithm") assert.Contains(t, err.Error(), "unsupported MAC algorithm")
} }
sftpdConf.MACs = nil
sftpdConf.KexAlgorithms = []string{"not a KEX"} sftpdConf.KexAlgorithms = []string{"not a KEX"}
err = sftpdConf.Initialize(configDir) err = sftpdConf.Initialize(configDir)
if assert.Error(t, err) { if assert.Error(t, err) {
assert.Contains(t, err.Error(), "unsupported key-exchange algorithm") assert.Contains(t, err.Error(), "unsupported key-exchange algorithm")
} }
sftpdConf.KexAlgorithms = nil
sftpdConf.HostKeyAlgorithms = []string{"not a host key algo"} sftpdConf.HostKeyAlgorithms = []string{"not a host key algo"}
err = sftpdConf.Initialize(configDir) err = sftpdConf.Initialize(configDir)
if assert.Error(t, err) { if assert.Error(t, err) {
@ -562,6 +564,7 @@ func TestBasicSFTPHandling(t *testing.T) {
assert.NotEmpty(t, sshCommands) assert.NotEmpty(t, sshCommands)
sshAuths := status.GetSupportedAuthsAsString() sshAuths := status.GetSupportedAuthsAsString()
assert.NotEmpty(t, sshAuths) assert.NotEmpty(t, sshAuths)
assert.NotEmpty(t, status.HostKeys[0].GetAlgosAsString())
} }
func TestBasicSFTPFsHandling(t *testing.T) { func TestBasicSFTPFsHandling(t *testing.T) {

View file

@ -313,7 +313,7 @@ func GetIntFromPointer(val *int64) int64 {
// GetTimeFromPointer returns the time value or now // GetTimeFromPointer returns the time value or now
func GetTimeFromPointer(val *time.Time) time.Time { func GetTimeFromPointer(val *time.Time) time.Time {
if val == nil { if val == nil {
return time.Now() return time.Unix(0, 0)
} }
return *val return *val
} }

View file

@ -17,7 +17,7 @@ package version
import "strings" import "strings"
const version = "2.4.5" const version = "2.4.6-dev"
var ( var (
commit = "" commit = ""

View file

@ -165,11 +165,11 @@ func (fs *S3Fs) Stat(name string) (os.FileInfo, error) {
// Some S3 providers (like SeaweedFS) remove the trailing '/' from object keys. // Some S3 providers (like SeaweedFS) remove the trailing '/' from object keys.
// So we check some common content types to detect if this is a "directory". // So we check some common content types to detect if this is a "directory".
isDir := util.Contains(s3DirMimeTypes, util.GetStringFromPointer(obj.ContentType)) isDir := util.Contains(s3DirMimeTypes, util.GetStringFromPointer(obj.ContentType))
if obj.ContentLength == 0 && !isDir { if util.GetIntFromPointer(obj.ContentLength) == 0 && !isDir {
_, err = fs.headObject(name + "/") _, err = fs.headObject(name + "/")
isDir = err == nil isDir = err == nil
} }
return updateFileInfoModTime(fs.getStorageID(), name, NewFileInfo(name, isDir, obj.ContentLength, return updateFileInfoModTime(fs.getStorageID(), name, NewFileInfo(name, isDir, util.GetIntFromPointer(obj.ContentLength),
util.GetTimeFromPointer(obj.LastModified), false)) util.GetTimeFromPointer(obj.LastModified), false))
} }
if !fs.IsNotExist(err) { if !fs.IsNotExist(err) {
@ -195,7 +195,7 @@ func (fs *S3Fs) getStatForDir(name string) (os.FileInfo, error) {
if err != nil { if err != nil {
return result, err return result, err
} }
return updateFileInfoModTime(fs.getStorageID(), name, NewFileInfo(name, true, obj.ContentLength, return updateFileInfoModTime(fs.getStorageID(), name, NewFileInfo(name, true, util.GetIntFromPointer(obj.ContentLength),
util.GetTimeFromPointer(obj.LastModified), false)) util.GetTimeFromPointer(obj.LastModified), false))
} }
@ -492,6 +492,7 @@ func (fs *S3Fs) ReadDir(dirname string) ([]os.FileInfo, error) {
} }
for _, fileObject := range page.Contents { for _, fileObject := range page.Contents {
objectModTime := util.GetTimeFromPointer(fileObject.LastModified) objectModTime := util.GetTimeFromPointer(fileObject.LastModified)
objectSize := util.GetIntFromPointer(fileObject.Size)
name, isDir := fs.resolve(fileObject.Key, prefix) name, isDir := fs.resolve(fileObject.Key, prefix)
if name == "" || name == "/" { if name == "" || name == "/" {
continue continue
@ -505,7 +506,7 @@ func (fs *S3Fs) ReadDir(dirname string) ([]os.FileInfo, error) {
if t, ok := modTimes[name]; ok { if t, ok := modTimes[name]; ok {
objectModTime = util.GetTimeFromMsecSinceEpoch(t) objectModTime = util.GetTimeFromMsecSinceEpoch(t)
} }
result = append(result, NewFileInfo(name, (isDir && fileObject.Size == 0), fileObject.Size, result = append(result, NewFileInfo(name, (isDir && objectSize == 0), objectSize,
objectModTime, false)) objectModTime, false))
} }
} }
@ -647,11 +648,12 @@ func (fs *S3Fs) GetDirSize(dirname string) (int, int64, error) {
} }
for _, fileObject := range page.Contents { for _, fileObject := range page.Contents {
isDir := strings.HasSuffix(util.GetStringFromPointer(fileObject.Key), "/") isDir := strings.HasSuffix(util.GetStringFromPointer(fileObject.Key), "/")
if isDir && fileObject.Size == 0 { objectSize := util.GetIntFromPointer(fileObject.Size)
if isDir && objectSize == 0 {
continue continue
} }
numFiles++ numFiles++
size += fileObject.Size size += objectSize
if numFiles%1000 == 0 { if numFiles%1000 == 0 {
fsLog(fs, logger.LevelDebug, "dirname %q scan in progress, files: %d, size: %d", dirname, numFiles, size) fsLog(fs, logger.LevelDebug, "dirname %q scan in progress, files: %d, size: %d", dirname, numFiles, size)
} }
@ -716,7 +718,8 @@ func (fs *S3Fs) Walk(root string, walkFn filepath.WalkFunc) error {
continue continue
} }
err := walkFn(util.GetStringFromPointer(fileObject.Key), err := walkFn(util.GetStringFromPointer(fileObject.Key),
NewFileInfo(name, isDir, fileObject.Size, util.GetTimeFromPointer(fileObject.LastModified), false), nil) NewFileInfo(name, isDir, util.GetIntFromPointer(fileObject.Size),
util.GetTimeFromPointer(fileObject.LastModified), false), nil)
if err != nil { if err != nil {
return err return err
} }
@ -794,10 +797,11 @@ func (fs *S3Fs) mkdirInternal(name string) error {
func (fs *S3Fs) hasContents(name string) (bool, error) { func (fs *S3Fs) hasContents(name string) (bool, error) {
prefix := fs.getPrefix(name) prefix := fs.getPrefix(name)
maxKeys := int32(2)
paginator := s3.NewListObjectsV2Paginator(fs.svc, &s3.ListObjectsV2Input{ paginator := s3.NewListObjectsV2Paginator(fs.svc, &s3.ListObjectsV2Input{
Bucket: aws.String(fs.config.Bucket), Bucket: aws.String(fs.config.Bucket),
Prefix: aws.String(prefix), Prefix: aws.String(prefix),
MaxKeys: 2, MaxKeys: &maxKeys,
}) })
if paginator.HasMorePages() { if paginator.HasMorePages() {
@ -891,7 +895,7 @@ func (fs *S3Fs) doMultipartCopy(source, target, contentType string, fileSize int
Bucket: aws.String(fs.config.Bucket), Bucket: aws.String(fs.config.Bucket),
CopySource: aws.String(source), CopySource: aws.String(source),
Key: aws.String(target), Key: aws.String(target),
PartNumber: partNum, PartNumber: &partNum,
UploadId: aws.String(uploadID), UploadId: aws.String(uploadID),
CopySourceRange: aws.String(fmt.Sprintf("bytes=%d-%d", partStart, partEnd-1)), CopySourceRange: aws.String(fmt.Sprintf("bytes=%d-%d", partStart, partEnd-1)),
}) })
@ -920,7 +924,7 @@ func (fs *S3Fs) doMultipartCopy(source, target, contentType string, fileSize int
partMutex.Lock() partMutex.Lock()
completedParts = append(completedParts, types.CompletedPart{ completedParts = append(completedParts, types.CompletedPart{
ETag: partResp.CopyPartResult.ETag, ETag: partResp.CopyPartResult.ETag,
PartNumber: partNum, PartNumber: &partNum,
}) })
partMutex.Unlock() partMutex.Unlock()
}(partNumber, start, end) }(partNumber, start, end)
@ -933,7 +937,13 @@ func (fs *S3Fs) doMultipartCopy(source, target, contentType string, fileSize int
return copyError return copyError
} }
sort.Slice(completedParts, func(i, j int) bool { sort.Slice(completedParts, func(i, j int) bool {
return completedParts[i].PartNumber < completedParts[j].PartNumber getPartNumber := func(number *int32) int32 {
if number == nil {
return 0
}
return *number
}
return getPartNumber(completedParts[i].PartNumber) < getPartNumber(completedParts[j].PartNumber)
}) })
completeCtx, completeCancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxTimeout)) completeCtx, completeCancelFn := context.WithDeadline(context.Background(), time.Now().Add(fs.ctxTimeout))

View file

@ -27,7 +27,7 @@ info:
SFTPGo supports groups to simplify the administration of multiple accounts by letting you assign settings once to a group, instead of multiple times to each individual user. SFTPGo supports groups to simplify the administration of multiple accounts by letting you assign settings once to a group, instead of multiple times to each individual user.
The SFTPGo WebClient allows end users to change their credentials, browse and manage their files in the browser and setup two-factor authentication which works with Authy, Google Authenticator and other compatible apps. The SFTPGo WebClient allows end users to change their credentials, browse and manage their files in the browser and setup two-factor authentication which works with Authy, Google Authenticator and other compatible apps.
From the WebClient each authorized user can also create HTTP/S links to externally share files and folders securely, by setting limits to the number of downloads/uploads, protecting the share with a password, limiting access by source IP address, setting an automatic expiration date. From the WebClient each authorized user can also create HTTP/S links to externally share files and folders securely, by setting limits to the number of downloads/uploads, protecting the share with a password, limiting access by source IP address, setting an automatic expiration date.
version: 2.4.5 version: 2.4.6
contact: contact:
name: API support name: API support
url: 'https://github.com/drakkan/sftpgo' url: 'https://github.com/drakkan/sftpgo'
@ -5532,6 +5532,10 @@ components:
type: string type: string
fingerprint: fingerprint:
type: string type: string
algorithms:
type: array
items:
type: string
SSHBinding: SSHBinding:
type: object type: object
properties: properties:

View file

@ -46,6 +46,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
<br> <br>
Fingerprint: "{{.Fingerprint}}" Fingerprint: "{{.Fingerprint}}"
<br> <br>
Algorithms: "{{.GetAlgosAsString}}"
<br>
{{end}} {{end}}
{{end}} {{end}}
</p> </p>