diff --git a/common/common_test.go b/common/common_test.go index cc610e36..596a101b 100644 --- a/common/common_test.go +++ b/common/common_test.go @@ -881,6 +881,39 @@ func TestGetTLSVersion(t *testing.T) { assert.Equal(t, uint16(tls.VersionTLS13), tlsVer) } +func TestCleanPath(t *testing.T) { + assert.Equal(t, "/", util.CleanPath("/")) + assert.Equal(t, "/", util.CleanPath(".")) + assert.Equal(t, "/", util.CleanPath("/.")) + assert.Equal(t, "/", util.CleanPath("/a/..")) + assert.Equal(t, "/a", util.CleanPath("/a/")) + assert.Equal(t, "/a", util.CleanPath("a/")) + // filepath.ToSlash does not touch \ as char on unix systems + // so os.PathSeparator is used for windows compatible tests + bslash := string(os.PathSeparator) + assert.Equal(t, "/", util.CleanPath(bslash)) + assert.Equal(t, "/", util.CleanPath(bslash+bslash)) + assert.Equal(t, "/a", util.CleanPath(bslash+"a"+bslash)) + assert.Equal(t, "/a", util.CleanPath("a"+bslash)) + assert.Equal(t, "/a/b/c", util.CleanPath(bslash+"a"+bslash+bslash+"b"+bslash+bslash+"c"+bslash)) + assert.Equal(t, "/C:/a", util.CleanPath("C:"+bslash+"a")) +} + +func TestUserRecentActivity(t *testing.T) { + u := dataprovider.User{} + res := u.HasRecentActivity() + assert.False(t, res) + u.LastLogin = util.GetTimeAsMsSinceEpoch(time.Now()) + res = u.HasRecentActivity() + assert.True(t, res) + u.LastLogin = util.GetTimeAsMsSinceEpoch(time.Now().Add(1 * time.Minute)) + res = u.HasRecentActivity() + assert.False(t, res) + u.LastLogin = util.GetTimeAsMsSinceEpoch(time.Now().Add(1 * time.Second)) + res = u.HasRecentActivity() + assert.True(t, res) +} + func BenchmarkBcryptHashing(b *testing.B) { bcryptPassword := "bcryptpassword" for i := 0; i < b.N; i++ { diff --git a/common/protocol_test.go b/common/protocol_test.go index 85e81c28..646d184e 100644 --- a/common/protocol_test.go +++ b/common/protocol_test.go @@ -837,13 +837,16 @@ func TestTruncateQuotaLimits(t *testing.T) { // cleanup err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - user.UsedQuotaFiles = 0 - user.UsedQuotaSize = 0 - _, err = httpdtest.UpdateQuotaUsage(user, "reset", http.StatusOK) - assert.NoError(t, err) - user.QuotaSize = 0 - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") - assert.NoError(t, err) + if user.Username == defaultUsername { + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.QuotaSize = 0 + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) + } } } } diff --git a/dataprovider/dataprovider.go b/dataprovider/dataprovider.go index eb82b233..ec48cf55 100644 --- a/dataprovider/dataprovider.go +++ b/dataprovider/dataprovider.go @@ -1122,9 +1122,7 @@ func UpdateAPIKeyLastUse(apiKey *APIKey) error { // UpdateLastLogin updates the last login field for the given SFTPGo user func UpdateLastLogin(user *User) { - lastLogin := util.GetTimeFromMsecSinceEpoch(user.LastLogin) - diff := -time.Until(lastLogin) - if diff < 0 || diff > lastLoginMinDelay { + if !isLastActivityRecent(user.LastLogin) { err := provider.updateLastLogin(user.Username) if err == nil { webDAVUsersCache.updateLastLogin(user.Username) @@ -1134,9 +1132,7 @@ func UpdateLastLogin(user *User) { // UpdateAdminLastLogin updates the last login field for the given SFTPGo admin func UpdateAdminLastLogin(admin *Admin) { - lastLogin := util.GetTimeFromMsecSinceEpoch(admin.LastLogin) - diff := -time.Until(lastLogin) - if diff < 0 || diff > lastLoginMinDelay { + if !isLastActivityRecent(admin.LastLogin) { provider.updateAdminLastLogin(admin.Username) //nolint:errcheck } } @@ -3375,3 +3371,12 @@ func getUserAndJSONForHook(username string) (User, []byte, error) { func providerLog(level logger.LogLevel, format string, v ...interface{}) { logger.Log(level, logSender, "", format, v...) } + +func isLastActivityRecent(lastActivity int64) bool { + lastActivityTime := util.GetTimeFromMsecSinceEpoch(lastActivity) + diff := -time.Until(lastActivityTime) + if diff < -10*time.Second { + return false + } + return diff < lastLoginMinDelay +} diff --git a/dataprovider/user.go b/dataprovider/user.go index b1d48c4f..5264ce67 100644 --- a/dataprovider/user.go +++ b/dataprovider/user.go @@ -161,12 +161,51 @@ func (u *User) getRootFs(connectionID string) (fs vfs.Fs, err error) { } } +func (u *User) checkDirWithParents(virtualDirPath, connectionID string) error { + dirs := util.GetDirsForVirtualPath(virtualDirPath) + for idx := len(dirs) - 1; idx >= 0; idx-- { + vPath := dirs[idx] + if vPath == "/" { + continue + } + fs, err := u.GetFilesystemForPath(vPath, connectionID) + if err != nil { + return fmt.Errorf("unable to get fs for path %#v: %w", vPath, err) + } + if fs.HasVirtualFolders() { + continue + } + fsPath, err := fs.ResolvePath(vPath) + if err != nil { + return fmt.Errorf("unable to resolve path %#v: %w", vPath, err) + } + _, err = fs.Stat(fsPath) + if err == nil { + continue + } + if fs.IsNotExist(err) { + err = fs.Mkdir(fsPath) + if err != nil { + return err + } + vfs.SetPathPermissions(fs, fsPath, u.GetUID(), u.GetGID()) + } else { + return fmt.Errorf("unable to stat path %#v: %w", vPath, err) + } + } + + return nil +} + // CheckFsRoot check the root directory for the main fs and the virtual folders. // It returns an error if the main filesystem cannot be created func (u *User) CheckFsRoot(connectionID string) error { if u.Filters.DisableFsChecks { return nil } + if isLastActivityRecent(u.LastLogin) { + return nil + } fs, err := u.GetFilesystemForPath("/", connectionID) if err != nil { logger.Warn(logSender, connectionID, "could not create main filesystem for user %#v err: %v", u.Username, err) @@ -180,15 +219,9 @@ func (u *User) CheckFsRoot(connectionID string) error { fs.CheckRootPath(u.Username, u.GetUID(), u.GetGID()) } // now check intermediary folders - fs, err = u.GetFilesystemForPath(path.Dir(v.VirtualPath), connectionID) - if err == nil && !fs.HasVirtualFolders() { - fsPath, err := fs.ResolvePath(v.VirtualPath) - if err != nil { - continue - } - err = fs.MkdirAll(fsPath, u.GetUID(), u.GetGID()) - logger.Debug(logSender, connectionID, "create intermediary dir to %#v, path %#v, err: %v", - v.VirtualPath, fsPath, err) + err = u.checkDirWithParents(path.Dir(v.VirtualPath), connectionID) + if err != nil { + logger.Warn(logSender, connectionID, "could not create intermediary dir to %#v, err: %v", v.VirtualPath, err) } } return nil @@ -1071,6 +1104,11 @@ func (u *User) GetHomeDir() string { return filepath.Clean(u.HomeDir) } +// HasRecentActivity returns true if the last user login is recent and so we can skip some expensive checks +func (u *User) HasRecentActivity() bool { + return isLastActivityRecent(u.LastLogin) +} + // HasQuotaRestrictions returns true if there are any disk quota restrictions func (u *User) HasQuotaRestrictions() bool { return u.QuotaFiles > 0 || u.QuotaSize > 0 diff --git a/ftpd/ftpd_test.go b/ftpd/ftpd_test.go index bda37e24..0e943224 100644 --- a/ftpd/ftpd_test.go +++ b/ftpd/ftpd_test.go @@ -1433,6 +1433,13 @@ func TestResume(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -1579,8 +1586,14 @@ func TestQuotaLimits(t *testing.T) { assert.NoError(t, err) user.QuotaFiles = 0 user.QuotaSize = 0 - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) + user.Password = defaultPassword + user.QuotaSize = 0 + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) @@ -1631,9 +1644,14 @@ func TestUploadMaxSize(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - user.Filters.MaxUploadFileSize = 65536000 - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) + user.Password = defaultPassword + user.Filters.MaxUploadFileSize = 65536000 + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) @@ -1823,12 +1841,17 @@ func TestRename(t *testing.T) { err = os.Remove(testFilePath) assert.NoError(t, err) if user.Username == defaultUsername { - user.Permissions = make(map[string][]string) - user.Permissions["/"] = allPerms - user, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") - assert.NoError(t, err) err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Permissions = make(map[string][]string) + user.Permissions["/"] = allPerms + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) @@ -1885,6 +1908,13 @@ func TestSymlink(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } err = os.Remove(testFilePath) @@ -1935,6 +1965,13 @@ func TestStat(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -2284,6 +2321,13 @@ func TestChtimes(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -2366,6 +2410,13 @@ func TestChmod(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -2523,6 +2574,13 @@ func TestHASH(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -2577,6 +2635,13 @@ func TestCombine(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } diff --git a/go.mod b/go.mod index a61a1e08..bc062969 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0 github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 - github.com/aws/aws-sdk-go v1.43.2 + github.com/aws/aws-sdk-go v1.43.5 github.com/cockroachdb/cockroach-go/v2 v2.2.8 github.com/coreos/go-oidc/v3 v3.1.0 github.com/eikenb/pipeat v0.0.0-20210730190139-06b3e6902001 @@ -26,8 +26,8 @@ require ( github.com/hashicorp/go-plugin v1.4.3 github.com/hashicorp/go-retryablehttp v0.7.0 github.com/jlaffaye/ftp v0.0.0-20201112195030-9aae4d151126 - github.com/klauspost/compress v1.14.3 - github.com/lestrrat-go/jwx v1.2.18 + github.com/klauspost/compress v1.14.4 + github.com/lestrrat-go/jwx v1.2.19 github.com/lib/pq v1.10.4 github.com/lithammer/shortuuid/v3 v3.0.7 github.com/mattn/go-sqlite3 v1.14.11 @@ -57,16 +57,16 @@ require ( gocloud.dev v0.24.0 golang.org/x/crypto v0.0.0-20220214200702-86341886e292 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd - golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 - golang.org/x/sys v0.0.0-20220209214540-3681064d5158 + golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b + golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 - google.golang.org/api v0.69.0 + google.golang.org/api v0.70.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 ) require ( cloud.google.com/go v0.100.2 // indirect - cloud.google.com/go/compute v1.3.0 // indirect + cloud.google.com/go/compute v1.5.0 // indirect cloud.google.com/go/iam v0.2.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v0.9.1 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -98,7 +98,7 @@ require ( github.com/lestrrat-go/iter v1.0.1 // indirect github.com/lestrrat-go/option v1.0.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/magiconair/properties v1.8.5 // indirect + github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect @@ -128,7 +128,7 @@ require ( golang.org/x/tools v0.1.9 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c // indirect + google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf // indirect google.golang.org/grpc v1.44.0 // indirect google.golang.org/protobuf v1.27.1 // indirect gopkg.in/ini.v1 v1.66.4 // indirect diff --git a/go.sum b/go.sum index dc3e81d3..343c02a3 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,9 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= cloud.google.com/go/compute v1.2.0/go.mod h1:xlogom/6gr8RJGBe7nT2eGsQYAFUbbv8dbC29qE3Xmw= -cloud.google.com/go/compute v1.3.0 h1:mPL/MzDDYHsh5tHRS9mhmhWlcgClCrCa6ApQCU6wnHI= cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0 h1:b1zWmYuuHz7gO9kDcM/EpHGr06UgsYNRpNJzI2kFiLM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= 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.5.0/go.mod h1:c4nNYR1qdq7eaZ+jSc5fonrQN2k3M7sWATcYTiakjEo= @@ -143,8 +144,8 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.40.34/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go v1.43.2 h1:T6LuKCNu8CYXXDn3xJoldh8FbdvuVH7C9aSuLNrlht0= -github.com/aws/aws-sdk-go v1.43.2/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= +github.com/aws/aws-sdk-go v1.43.5 h1:N7arnx54E4QyW69c45UW5o8j2DCSjzpoxzJW3yU6OSo= +github.com/aws/aws-sdk-go v1.43.5/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/config v1.7.0/go.mod h1:w9+nMZ7soXCe5nT46Ri354SNhXDQ6v+V5wqDjnZE+GY= github.com/aws/aws-sdk-go-v2/credentials v1.4.0/go.mod h1:dgGR+Qq7Wjcd4AOAW5Rf5Tnv3+x7ed6kETXyS9WCuAY= @@ -513,8 +514,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.14.3 h1:DQv1WP+iS4srNjibdnHtqu8JNWCDMluj5NzPnFJsnvk= -github.com/klauspost/compress v1.14.3/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.14.4 h1:eijASRJcobkVtSt81Olfh7JX43osYLwy5krOJo6YEu4= +github.com/klauspost/compress v1.14.4/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.11 h1:i2lw1Pm7Yi/4O6XCSyJWqEHI2MDw2FzUK6o/D21xn2A= github.com/klauspost/cpuid/v2 v2.0.11/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= @@ -543,8 +544,8 @@ github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++ github.com/lestrrat-go/iter v1.0.1 h1:q8faalr2dY6o8bV45uwrxq12bRa1ezKrB6oM9FUgN4A= github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= github.com/lestrrat-go/jwx v1.2.6/go.mod h1:tJuGuAI3LC71IicTx82Mz1n3w9woAs2bYJZpkjJQ5aU= -github.com/lestrrat-go/jwx v1.2.18 h1:RV4hcTRUlPVYUnGqATKXEojoOsLexoU8Na4KheVzxQ8= -github.com/lestrrat-go/jwx v1.2.18/go.mod h1:bWTBO7IHHVMtNunM8so9MT8wD+euEY1PzGEyCnuI2qM= +github.com/lestrrat-go/jwx v1.2.19 h1:qxxLmAXNwZpTTvjc4PH21nT7I4wPK6lVv3lVNcZPnUk= +github.com/lestrrat-go/jwx v1.2.19/go.mod h1:bWTBO7IHHVMtNunM8so9MT8wD+euEY1PzGEyCnuI2qM= github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -560,8 +561,9 @@ github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaK github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -854,8 +856,9 @@ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -953,8 +956,9 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00= +golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1087,8 +1091,9 @@ google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tD google.golang.org/api v0.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSimebM= google.golang.org/api v0.66.0/go.mod h1:I1dmXYpX7HGwz/ejRxwQp2qj5bFAz93HiCU1C1oYd9M= google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.69.0 h1:yHW5s2SFyDapr/43kYtIQmoaaFVW4baLMLwqV4auj2A= google.golang.org/api v0.69.0/go.mod h1:boanBiw+h5c3s+tBPgEzLDRHfFLWV0qXxRHz3ws7C80= +google.golang.org/api v0.70.0 h1:67zQnAE0T2rB0A3CwLSas0K+SbVzSxP+zTLkQLexeiw= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1178,8 +1183,9 @@ google.golang.org/genproto v0.0.0-20220201184016-50beb8ab5c44/go.mod h1:5CzLGKJ6 google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20220211171837-173942840c17/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/genproto v0.0.0-20220216160803-4663080d8bc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c h1:TU4rFa5APdKTq0s6B7WTsH6Xmx0Knj86s6Biz56mErE= google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf h1:SVYXkUz2yZS9FWb2Gm8ivSlbNQzL2Z/NpPKE3RG2jWk= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= diff --git a/httpd/middleware.go b/httpd/middleware.go index 77e88b2c..9408c0d7 100644 --- a/httpd/middleware.go +++ b/httpd/middleware.go @@ -5,7 +5,6 @@ import ( "fmt" "net/http" "strings" - "time" "github.com/go-chi/jwtauth/v5" "github.com/lestrrat-go/jwx/jwt" @@ -406,15 +405,11 @@ func authenticateUserWithAPIKey(username, keyID string, tokenAuth *jwtauth.JWTAu updateLoginMetrics(&user, dataprovider.LoginMethodPassword, ipAddr, err) return err } - lastLogin := util.GetTimeFromMsecSinceEpoch(user.LastLogin) - diff := -time.Until(lastLogin) - if diff < 0 || diff > 10*time.Minute { - defer user.CloseFs() //nolint:errcheck - err = user.CheckFsRoot(connectionID) - if err != nil { - updateLoginMetrics(&user, dataprovider.LoginMethodPassword, ipAddr, common.ErrInternalFailure) - return common.ErrInternalFailure - } + defer user.CloseFs() //nolint:errcheck + err = user.CheckFsRoot(connectionID) + if err != nil { + updateLoginMetrics(&user, dataprovider.LoginMethodPassword, ipAddr, common.ErrInternalFailure) + return common.ErrInternalFailure } c := jwtTokenClaims{ Username: user.Username, diff --git a/sftpd/sftpd_test.go b/sftpd/sftpd_test.go index 524d206c..4046be9b 100644 --- a/sftpd/sftpd_test.go +++ b/sftpd/sftpd_test.go @@ -762,6 +762,13 @@ func TestOpenReadWritePerm(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -1063,6 +1070,13 @@ func TestUploadResume(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -1290,6 +1304,13 @@ func TestStat(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -1340,6 +1361,13 @@ func TestStatChownChmod(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -1384,11 +1412,13 @@ func TestSFTPFsLoginWrongFingerprint(t *testing.T) { sftpUser.FsConfig.SFTPConfig.Fingerprints = []string{"wrong"} _, _, err = httpdtest.UpdateUser(sftpUser, http.StatusOK, "") assert.NoError(t, err) - _, _, err = getSftpClient(sftpUser, usePubKey) - assert.Error(t, err) - - _, err = runSSHCommand("md5sum", sftpUser, usePubKey) - assert.Error(t, err) + conn, client, err = getSftpClient(sftpUser, usePubKey) + if assert.NoError(t, err) { + defer conn.Close() + defer client.Close() + err = checkBasicSFTP(client) + assert.Error(t, err) + } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) assert.NoError(t, err) @@ -1438,6 +1468,13 @@ func TestChtimes(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -3816,13 +3853,14 @@ func TestQuotaFileReplace(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - user.UsedQuotaFiles = 0 - user.UsedQuotaSize = 0 - _, err = httpdtest.UpdateQuotaUsage(user, "reset", http.StatusOK) + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 user.QuotaSize = 0 - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") - assert.NoError(t, err) + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) @@ -3914,10 +3952,13 @@ func TestQuotaRename(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - user.UsedQuotaFiles = 0 - user.UsedQuotaSize = 0 - _, err = httpdtest.UpdateQuotaUsage(user, "reset", http.StatusOK) + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -4078,10 +4119,13 @@ func TestQuotaLimits(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - user.UsedQuotaFiles = 0 - user.UsedQuotaSize = 0 - _, err = httpdtest.UpdateQuotaUsage(user, "reset", http.StatusOK) + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } err = os.Remove(testFilePath) @@ -5078,13 +5122,14 @@ func TestTruncateQuotaLimits(t *testing.T) { // cleanup err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - user.UsedQuotaFiles = 0 - user.UsedQuotaSize = 0 - _, err = httpdtest.UpdateQuotaUsage(user, "reset", http.StatusOK) + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 user.QuotaSize = 0 - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") - assert.NoError(t, err) + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } } @@ -7323,10 +7368,15 @@ func TestRootDirCommands(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 user.Permissions = make(map[string][]string) user.Permissions["/"] = []string{dataprovider.PermAny} - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") - assert.NoError(t, err) + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) @@ -8900,6 +8950,13 @@ func TestSCPBasicHandling(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } @@ -8975,6 +9032,13 @@ func TestSCPUploadFileOverwrite(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } err = os.Remove(testFilePath) @@ -9043,6 +9107,13 @@ func TestSCPRecursive(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } diff --git a/vfs/azblobfs.go b/vfs/azblobfs.go index 0a59c075..061eadfc 100644 --- a/vfs/azblobfs.go +++ b/vfs/azblobfs.go @@ -353,11 +353,6 @@ func (fs *AzureBlobFs) Mkdir(name string) error { return w.Close() } -// MkdirAll does nothing, we don't have folder -func (*AzureBlobFs) MkdirAll(name string, uid int, gid int) error { - return nil -} - // Symlink creates source as a symbolic link to target. func (*AzureBlobFs) Symlink(source, target string) error { return ErrVfsUnsupported diff --git a/vfs/gcsfs.go b/vfs/gcsfs.go index 12429bbb..e2b08a1f 100644 --- a/vfs/gcsfs.go +++ b/vfs/gcsfs.go @@ -317,11 +317,6 @@ func (fs *GCSFs) Mkdir(name string) error { return w.Close() } -// MkdirAll does nothing, we don't have folder -func (*GCSFs) MkdirAll(name string, uid int, gid int) error { - return nil -} - // Symlink creates source as a symbolic link to target. func (*GCSFs) Symlink(source, target string) error { return ErrVfsUnsupported diff --git a/vfs/osfs.go b/vfs/osfs.go index 8b0f3a9e..43183327 100644 --- a/vfs/osfs.go +++ b/vfs/osfs.go @@ -128,13 +128,6 @@ func (*OsFs) Mkdir(name string) error { return os.Mkdir(name, os.ModePerm) } -// MkdirAll creates a directory named path, along with any necessary parents, -// and returns nil, or else returns an error. -// If path is already a directory, MkdirAll does nothing and returns nil. -func (fs *OsFs) MkdirAll(name string, uid int, gid int) error { - return fs.createMissingDirs(name, uid, gid) -} - // Symlink creates source as a symbolic link to target. func (*OsFs) Symlink(source, target string) error { return os.Symlink(source, target) @@ -418,23 +411,6 @@ func (fs *OsFs) isSubDir(sub string) error { return nil } -func (fs *OsFs) createMissingDirs(filePath string, uid, gid int) error { - dirsToCreate, err := fs.findNonexistentDirs(filePath) - if err != nil { - return err - } - last := len(dirsToCreate) - 1 - for i := range dirsToCreate { - d := dirsToCreate[last-i] - if err := os.Mkdir(d, os.ModePerm); err != nil { - fsLog(fs, logger.LevelError, "error creating missing dir: %#v", d) - return err - } - SetPathPermissions(fs, d, uid, gid) - } - return nil -} - // GetMimeType returns the content type func (fs *OsFs) GetMimeType(name string) (string, error) { f, err := os.OpenFile(name, os.O_RDONLY, 0) diff --git a/vfs/s3fs.go b/vfs/s3fs.go index 12ef9413..97a97902 100644 --- a/vfs/s3fs.go +++ b/vfs/s3fs.go @@ -90,22 +90,7 @@ func NewS3Fs(connectionID, localTempDir, mountPath string, config S3FsConfig) (F if fs.config.ForcePathStyle { awsConfig.S3ForcePathStyle = aws.Bool(true) } - if fs.config.UploadPartSize == 0 { - fs.config.UploadPartSize = s3manager.DefaultUploadPartSize - } else { - fs.config.UploadPartSize *= 1024 * 1024 - } - if fs.config.UploadConcurrency == 0 { - fs.config.UploadConcurrency = s3manager.DefaultUploadConcurrency - } - if fs.config.DownloadPartSize == 0 { - fs.config.DownloadPartSize = s3manager.DefaultDownloadPartSize - } else { - fs.config.DownloadPartSize *= 1024 * 1024 - } - if fs.config.DownloadConcurrency == 0 { - fs.config.DownloadConcurrency = s3manager.DefaultDownloadConcurrency - } + fs.setConfigDefaults() sessOpts := session.Options{ Config: *awsConfig, @@ -392,11 +377,6 @@ func (fs *S3Fs) Mkdir(name string) error { return w.Close() } -// MkdirAll does nothing, we don't have folder -func (*S3Fs) MkdirAll(name string, uid int, gid int) error { - return nil -} - // Symlink creates source as a symbolic link to target. func (*S3Fs) Symlink(source, target string) error { return ErrVfsUnsupported @@ -742,6 +722,29 @@ func (fs *S3Fs) checkIfBucketExists() error { return err } +func (fs *S3Fs) setConfigDefaults() { + if fs.config.UploadPartSize == 0 { + fs.config.UploadPartSize = s3manager.DefaultUploadPartSize + } else { + if fs.config.UploadPartSize < 1024*1024 { + fs.config.UploadPartSize *= 1024 * 1024 + } + } + if fs.config.UploadConcurrency == 0 { + fs.config.UploadConcurrency = s3manager.DefaultUploadConcurrency + } + if fs.config.DownloadPartSize == 0 { + fs.config.DownloadPartSize = s3manager.DefaultDownloadPartSize + } else { + if fs.config.DownloadPartSize < 1024*1024 { + fs.config.DownloadPartSize *= 1024 * 1024 + } + } + if fs.config.DownloadConcurrency == 0 { + fs.config.DownloadConcurrency = s3manager.DefaultDownloadConcurrency + } +} + func (fs *S3Fs) hasContents(name string) (bool, error) { prefix := "" if name != "/" && name != "." { diff --git a/vfs/sftpfs.go b/vfs/sftpfs.go index 9c3800a5..91e2666e 100644 --- a/vfs/sftpfs.go +++ b/vfs/sftpfs.go @@ -349,16 +349,6 @@ func (fs *SFTPFs) Mkdir(name string) error { return fs.sftpClient.Mkdir(name) } -// MkdirAll creates a directory named path, along with any necessary parents, -// and returns nil, or else returns an error. -// If path is already a directory, MkdirAll does nothing and returns nil. -func (fs *SFTPFs) MkdirAll(name string, uid int, gid int) error { - if err := fs.checkConnection(); err != nil { - return err - } - return fs.sftpClient.MkdirAll(name) -} - // Symlink creates source as a symbolic link to target. func (fs *SFTPFs) Symlink(source, target string) error { if err := fs.checkConnection(); err != nil { @@ -459,7 +449,10 @@ func (fs *SFTPFs) CheckRootPath(username string, uid int, gid int) bool { if fs.config.Prefix == "/" { return true } - if err := fs.MkdirAll(fs.config.Prefix, uid, gid); err != nil { + if err := fs.checkConnection(); err != nil { + return false + } + if err := fs.sftpClient.MkdirAll(fs.config.Prefix); err != nil { fsLog(fs, logger.LevelDebug, "error creating root directory %#v for user %#v: %v", fs.config.Prefix, username, err) return false } diff --git a/vfs/vfs.go b/vfs/vfs.go index cf8d1b06..eee2768a 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -73,7 +73,6 @@ type Fs interface { Rename(source, target string) error Remove(name string, isDir bool) error Mkdir(name string) error - MkdirAll(name string, uid int, gid int) error Symlink(source, target string) error Chown(name string, uid int, gid int) error Chmod(name string, mode os.FileMode) error diff --git a/webdavd/webdavd_test.go b/webdavd/webdavd_test.go index 9e674e4a..75c3864d 100644 --- a/webdavd/webdavd_test.go +++ b/webdavd/webdavd_test.go @@ -576,6 +576,13 @@ func TestBasicHandling(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) @@ -1484,10 +1491,15 @@ func TestQuotaLimits(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) + _, err = httpdtest.RemoveUser(user, http.StatusOK) + assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 user.QuotaFiles = 0 user.QuotaSize = 0 - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") - assert.NoError(t, err) + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) @@ -1581,9 +1593,14 @@ func TestUploadMaxSize(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - user.Filters.MaxUploadFileSize = 65536000 - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) + user.Filters.MaxUploadFileSize = 65536000 + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK) @@ -2195,9 +2212,14 @@ func TestMiscCommands(t *testing.T) { if user.Username == defaultUsername { err = os.RemoveAll(user.GetHomeDir()) assert.NoError(t, err) - user.QuotaFiles = 0 - _, _, err = httpdtest.UpdateUser(user, http.StatusOK, "") + _, err = httpdtest.RemoveUser(user, http.StatusOK) assert.NoError(t, err) + user.Password = defaultPassword + user.ID = 0 + user.CreatedAt = 0 + user.QuotaFiles = 0 + _, resp, err := httpdtest.AddUser(user, http.StatusCreated) + assert.NoError(t, err, string(resp)) } } _, err = httpdtest.RemoveUser(sftpUser, http.StatusOK)