Pārlūkot izejas kodu

upgrade golangci-lint to v2

Signed-off-by: Nicola Murino <[email protected]>
Nicola Murino 7 mēneši atpakaļ
vecāks
revīzija
2255c5f000

+ 1 - 2
.github/workflows/development.yml

@@ -614,7 +614,6 @@ jobs:
           go-version: '1.24'
       - uses: actions/checkout@v4
       - name: Run golangci-lint
-        uses: golangci/golangci-lint-action@v6
+        uses: golangci/golangci-lint-action@v7
         with:
-          args: --timeout=10m
           version: latest

+ 44 - 42
.golangci.yml

@@ -1,52 +1,54 @@
+version: "2"
 run:
-  timeout: 10m
   issues-exit-code: 1
   tests: true
-
-
-linters-settings:
-  dupl:
-    threshold: 150
-  errcheck:
-    check-type-assertions: false
-    check-blank: false
-  goconst:
-    min-len: 3
-    min-occurrences: 3
-  gocyclo:
-    min-complexity: 15
-  gofmt:
-    simplify: true
-  goimports:
-    local-prefixes: github.com/drakkan/sftpgo
-  #govet:
-    # report about shadowed variables
-    #check-shadowing: true
-    #enable:
-    #  - fieldalignment
-
-issues:
-  include:
-    - EXC0002
-    - EXC0012
-    - EXC0013
-    - EXC0014
-    - EXC0015
-
 linters:
   enable:
+    - bodyclose
+    - dogsled
+    - dupl
     - goconst
-    - errcheck
-    - gofmt
-    - goimports
+    - gocyclo
+    - misspell
     - revive
+    - rowserrcheck
     - unconvert
     - unparam
-    - bodyclose
-    - gocyclo
-    - misspell
     - whitespace
-    - dupl
-    - rowserrcheck
-    - dogsled
-    - govet
+  settings:
+    dupl:
+      threshold: 150
+    errcheck:
+      check-type-assertions: false
+      check-blank: false
+    goconst:
+      min-len: 3
+      min-occurrences: 3
+    gocyclo:
+      min-complexity: 15
+  exclusions:
+    generated: lax
+    presets:
+      - common-false-positives
+      - legacy
+      - std-error-handling
+    paths:
+      - third_party$
+      - builtin$
+      - examples$
+formatters:
+  enable:
+    - gofmt
+    - goimports
+  settings:
+    gofmt:
+      simplify: true
+    goimports:
+      local-prefixes:
+        - github.com/drakkan/sftpgo
+  exclusions:
+    generated: lax
+    paths:
+      - third_party$
+      - builtin$
+      - examples$

+ 4 - 3
internal/cmd/initprovider.go

@@ -78,11 +78,12 @@ Please take a look at the usage below to customize the options.`,
 			providerConf.Actions.ExecuteOn = nil
 			logger.InfoToConsole("Initializing provider: %q config file: %q", providerConf.Driver, viper.ConfigFileUsed())
 			err = dataprovider.InitializeDatabase(providerConf, configDir)
-			if err == nil {
+			switch err {
+			case nil:
 				logger.InfoToConsole("Data provider successfully initialized/updated")
-			} else if err == dataprovider.ErrNoInitRequired {
+			case dataprovider.ErrNoInitRequired:
 				logger.InfoToConsole("%v", err.Error())
-			} else {
+			default:
 				logger.ErrorToConsole("Unable to initialize/update the data provider: %v", err)
 				os.Exit(1)
 			}

+ 4 - 3
internal/common/common_test.go

@@ -64,7 +64,7 @@ func (c *fakeConnection) AddUser(user dataprovider.User) error {
 	if err != nil {
 		return err
 	}
-	c.BaseConnection.User = user
+	c.User = user
 	return nil
 }
 
@@ -999,9 +999,10 @@ func TestConnectionStatus(t *testing.T) {
 	assert.Len(t, stats, 3)
 	for _, stat := range stats {
 		assert.Equal(t, stat.Username, username)
-		if stat.ConnectionID == "SFTP_id1" {
+		switch stat.ConnectionID {
+		case "SFTP_id1":
 			assert.Len(t, stat.Transfers, 2)
-		} else if stat.ConnectionID == "DAV_id3" {
+		case "DAV_id3":
 			assert.Len(t, stat.Transfers, 1)
 		}
 	}

+ 1 - 4
internal/common/connection.go

@@ -771,10 +771,7 @@ func (c *BaseConnection) Copy(virtualSourcePath, virtualTargetPath string) error
 			return err
 		}
 	}
-	createTargetDir := true
-	if dstInfo != nil && dstInfo.IsDir() {
-		createTargetDir = false
-	}
+	createTargetDir := dstInfo == nil || !dstInfo.IsDir()
 	if err := c.checkCopy(srcInfo, dstInfo, virtualSourcePath, destPath); err != nil {
 		return err
 	}

+ 4 - 4
internal/common/defenderdb.go

@@ -62,7 +62,7 @@ func (d *dbDefender) GetHost(ip string) (dataprovider.DefenderEntry, error) {
 // and increase ban time if the IP is found.
 // This method must be called as soon as the client connects
 func (d *dbDefender) IsBanned(ip, protocol string) bool {
-	if d.baseDefender.isBanned(ip, protocol) {
+	if d.isBanned(ip, protocol) {
 		return true
 	}
 
@@ -95,15 +95,15 @@ func (d *dbDefender) AddEvent(ip, protocol string, event HostEvent) bool {
 		return true
 	}
 
-	score := d.baseDefender.getScore(event)
+	score := d.getScore(event)
 
 	host, err := dataprovider.AddDefenderEvent(ip, score, d.getStartObservationTime())
 	if err != nil {
 		return false
 	}
-	d.baseDefender.logEvent(ip, protocol, event, host.Score)
+	d.logEvent(ip, protocol, event, host.Score)
 	if host.Score > d.config.Threshold {
-		d.baseDefender.logBan(ip, protocol)
+		d.logBan(ip, protocol)
 		banTime := time.Now().Add(time.Duration(d.config.BanTime) * time.Minute)
 		err = dataprovider.SetDefenderBanTime(ip, util.GetTimeAsMsSinceEpoch(banTime))
 		if err == nil {

+ 5 - 5
internal/common/defendermem.go

@@ -148,7 +148,7 @@ func (d *memoryDefender) IsBanned(ip, protocol string) bool {
 
 	defer d.RUnlock()
 
-	return d.baseDefender.isBanned(ip, protocol)
+	return d.isBanned(ip, protocol)
 }
 
 // DeleteHost removes the specified IP from the defender lists
@@ -188,7 +188,7 @@ func (d *memoryDefender) AddEvent(ip, protocol string, event HostEvent) bool {
 		delete(d.banned, ip)
 	}
 
-	score := d.baseDefender.getScore(event)
+	score := d.getScore(event)
 
 	ev := hostEvent{
 		dateTime: time.Now(),
@@ -207,11 +207,11 @@ func (d *memoryDefender) AddEvent(ip, protocol string, event HostEvent) bool {
 				idx++
 			}
 		}
-		d.baseDefender.logEvent(ip, protocol, event, hs.TotalScore)
+		d.logEvent(ip, protocol, event, hs.TotalScore)
 
 		hs.Events = hs.Events[:idx]
 		if hs.TotalScore >= d.config.Threshold {
-			d.baseDefender.logBan(ip, protocol)
+			d.logBan(ip, protocol)
 			d.banned[ip] = time.Now().Add(time.Duration(d.config.BanTime) * time.Minute)
 			delete(d.hosts, ip)
 			d.cleanupBanned()
@@ -225,7 +225,7 @@ func (d *memoryDefender) AddEvent(ip, protocol string, event HostEvent) bool {
 			d.hosts[ip] = hs
 		}
 	} else {
-		d.baseDefender.logEvent(ip, protocol, event, ev.score)
+		d.logEvent(ip, protocol, event, ev.score)
 		d.hosts[ip] = hostScore{
 			TotalScore: ev.score,
 			Events:     []hostEvent{ev},

+ 1 - 1
internal/common/transfer.go

@@ -35,7 +35,7 @@ var (
 )
 
 // BaseTransfer contains protocols common transfer details for an upload or a download.
-type BaseTransfer struct { //nolint:maligned
+type BaseTransfer struct {
 	ID              int64
 	BytesSent       atomic.Int64
 	BytesReceived   atomic.Int64

+ 3 - 2
internal/dataprovider/dataprovider.go

@@ -3700,7 +3700,8 @@ func comparePbkdf2PasswordAndHash(password, hashedPassword string) (bool, error)
 }
 
 func getSSLMode() string {
-	if config.Driver == PGSQLDataProviderName || config.Driver == CockroachDataProviderName {
+	switch config.Driver {
+	case PGSQLDataProviderName, CockroachDataProviderName:
 		switch config.SSLMode {
 		case 0:
 			return "disable"
@@ -3715,7 +3716,7 @@ func getSSLMode() string {
 		case 5:
 			return "allow"
 		}
-	} else if config.Driver == MySQLDataProviderName {
+	case MySQLDataProviderName:
 		if config.requireCustomTLSForMySQL() {
 			return "custom"
 		}

+ 1 - 1
internal/ftpd/handler.go

@@ -287,7 +287,7 @@ func (c *Connection) RemoveDir(name string) error {
 func (c *Connection) Symlink(oldname, newname string) error {
 	c.UpdateLastActivity()
 
-	return c.BaseConnection.CreateSymlink(oldname, newname)
+	return c.CreateSymlink(oldname, newname)
 }
 
 // ReadDir implements ClientDriverExtensionFilelist

+ 1 - 1
internal/ftpd/transfer.go

@@ -136,7 +136,7 @@ func (t *transfer) closeIO() error {
 	} else if t.reader != nil {
 		err = t.reader.Close()
 		if metadater, ok := t.reader.(vfs.Metadater); ok {
-			t.BaseTransfer.SetMetadata(metadater.Metadata())
+			t.SetMetadata(metadater.Metadata())
 		}
 	}
 	return err

+ 3 - 3
internal/httpd/api_configs.go

@@ -66,7 +66,7 @@ func testSMTPConfig(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 	if req.AuthType == 3 {
-		if err := req.Config.OAuth2.Validate(); err != nil {
+		if err := req.OAuth2.Validate(); err != nil {
 			sendAPIResponse(w, r, err, "", http.StatusBadRequest)
 			return
 		}
@@ -106,10 +106,10 @@ func (s *httpdServer) handleSMTPOAuth2TokenRequestPost(w http.ResponseWriter, r
 		}
 		configs.SetNilsToEmpty()
 		if err := configs.SMTP.TryDecrypt(); err == nil {
-			req.OAuth2Config.ClientSecret = configs.SMTP.OAuth2.ClientSecret.GetPayload()
+			req.ClientSecret = configs.SMTP.OAuth2.ClientSecret.GetPayload()
 		}
 	}
-	cfg := req.OAuth2Config.GetOAuth2()
+	cfg := req.GetOAuth2()
 	cfg.RedirectURL = req.BaseRedirectURL + webOAuth2RedirectPath
 	clientSecret := kms.NewPlainSecret(cfg.ClientSecret)
 	clientSecret.SetAdditionalData(xid.New().String())

+ 1 - 1
internal/httpd/file.go

@@ -126,7 +126,7 @@ func (f *httpdFile) closeIO() error {
 	} else if f.reader != nil {
 		err = f.reader.Close()
 		if metadater, ok := f.reader.(vfs.Metadater); ok {
-			f.BaseTransfer.SetMetadata(metadater.Metadata())
+			f.SetMetadata(metadater.Metadata())
 		}
 	}
 	return err

+ 6 - 6
internal/httpd/httpd_test.go

@@ -1364,19 +1364,19 @@ func TestGroupSettingsOverride(t *testing.T) {
 			switch f.Name {
 			case folderName1:
 				assert.Equal(t, mappedPath1, f.MappedPath)
-				assert.Equal(t, 3, f.BaseVirtualFolder.FsConfig.OSConfig.ReadBufferSize)
-				assert.Equal(t, 5, f.BaseVirtualFolder.FsConfig.OSConfig.WriteBufferSize)
+				assert.Equal(t, 3, f.FsConfig.OSConfig.ReadBufferSize)
+				assert.Equal(t, 5, f.FsConfig.OSConfig.WriteBufferSize)
 				assert.True(t, slices.Contains([]string{"/vdir1", "/vdir2"}, f.VirtualPath))
 			case folderName2:
 				assert.Equal(t, mappedPath2, f.MappedPath)
 				assert.Equal(t, "/vdir3", f.VirtualPath)
-				assert.Equal(t, 0, f.BaseVirtualFolder.FsConfig.OSConfig.ReadBufferSize)
-				assert.Equal(t, 0, f.BaseVirtualFolder.FsConfig.OSConfig.WriteBufferSize)
+				assert.Equal(t, 0, f.FsConfig.OSConfig.ReadBufferSize)
+				assert.Equal(t, 0, f.FsConfig.OSConfig.WriteBufferSize)
 			case folderName3:
 				assert.Equal(t, mappedPath3, f.MappedPath)
 				assert.Equal(t, "/vdir4", f.VirtualPath)
-				assert.Equal(t, 1, f.BaseVirtualFolder.FsConfig.OSConfig.ReadBufferSize)
-				assert.Equal(t, 2, f.BaseVirtualFolder.FsConfig.OSConfig.WriteBufferSize)
+				assert.Equal(t, 1, f.FsConfig.OSConfig.ReadBufferSize)
+				assert.Equal(t, 2, f.FsConfig.OSConfig.WriteBufferSize)
 			}
 		}
 	}

+ 4 - 3
internal/sftpd/server.go

@@ -857,11 +857,12 @@ func (c *Configuration) generateDefaultHostKeys(configDir string) error {
 		if _, err = os.Stat(autoFile); errors.Is(err, fs.ErrNotExist) {
 			logger.Info(logSender, "", "No host keys configured and %q does not exist; try to create a new host key", autoFile)
 			logger.InfoToConsole("No host keys configured and %q does not exist; try to create a new host key", autoFile)
-			if k == defaultPrivateRSAKeyName {
+			switch k {
+			case defaultPrivateRSAKeyName:
 				err = util.GenerateRSAKeys(autoFile)
-			} else if k == defaultPrivateECDSAKeyName {
+			case defaultPrivateECDSAKeyName:
 				err = util.GenerateECDSAKeys(autoFile)
-			} else {
+			default:
 				err = util.GenerateEd25519Keys(autoFile)
 			}
 			if err != nil {

+ 6 - 5
internal/sftpd/ssh_cmd.go

@@ -201,15 +201,16 @@ func (c *sshCommand) updateQuota(sshDestPath string, filesNum int, filesSize int
 
 func (c *sshCommand) handleHashCommands() error {
 	var h hash.Hash
-	if c.command == "md5sum" {
+	switch c.command {
+	case "md5sum":
 		h = md5.New()
-	} else if c.command == "sha1sum" {
+	case "sha1sum":
 		h = sha1.New()
-	} else if c.command == "sha256sum" {
+	case "sha256sum":
 		h = sha256.New()
-	} else if c.command == "sha384sum" {
+	case "sha384sum":
 		h = sha512.New384()
-	} else {
+	default:
 		h = sha512.New()
 	}
 	var response string

+ 1 - 1
internal/sftpd/transfer.go

@@ -177,7 +177,7 @@ func (t *transfer) closeIO() error {
 	} else if t.readerAt != nil {
 		err = t.readerAt.Close()
 		if metadater, ok := t.readerAt.(vfs.Metadater); ok {
-			t.BaseTransfer.SetMetadata(metadater.Metadata())
+			t.SetMetadata(metadater.Metadata())
 		}
 	}
 	return err

+ 2 - 2
internal/util/timeoutlistener.go

@@ -60,7 +60,7 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 		c.BytesReadFromDeadline.Store(0)
 		// we set both read and write deadlines here otherwise after the request
 		// is read writing the response fails with an i/o timeout error
-		err = c.Conn.SetDeadline(time.Now().Add(c.ReadTimeout))
+		err = c.SetDeadline(time.Now().Add(c.ReadTimeout))
 		if err != nil {
 			return 0, err
 		}
@@ -75,7 +75,7 @@ func (c *Conn) Write(b []byte) (n int, err error) {
 		c.BytesWrittenFromDeadline.Store(0)
 		// we extend the read deadline too, not sure it's necessary,
 		// but it doesn't hurt
-		err = c.Conn.SetDeadline(time.Now().Add(c.WriteTimeout))
+		err = c.SetDeadline(time.Now().Add(c.WriteTimeout))
 		if err != nil {
 			return
 		}

+ 3 - 6
internal/util/util.go

@@ -235,7 +235,7 @@ func ParseBytes(s string) (int64, error) {
 	lastDigit := 0
 	hasComma := false
 	for _, r := range s {
-		if !(unicode.IsDigit(r) || r == '.' || r == ',') {
+		if !unicode.IsDigit(r) && r != '.' && r != ',' {
 			break
 		}
 		if r == ',' {
@@ -246,7 +246,7 @@ func ParseBytes(s string) (int64, error) {
 
 	num := s[:lastDigit]
 	if hasComma {
-		num = strings.Replace(num, ",", "", -1)
+		num = strings.ReplaceAll(num, ",", "")
 	}
 
 	f, err := strconv.ParseFloat(num, 64)
@@ -489,10 +489,7 @@ func GetDirsForVirtualPath(virtualPath string) []string {
 		}
 	}
 	dirsForPath := []string{virtualPath}
-	for {
-		if virtualPath == "/" {
-			break
-		}
+	for virtualPath != "/" {
 		virtualPath = path.Dir(virtualPath)
 		dirsForPath = append(dirsForPath, virtualPath)
 	}

+ 7 - 7
internal/vfs/azblobfs.go

@@ -561,7 +561,7 @@ func (fs *AzureBlobFs) GetDirSize(dirname string) (int, int64, error) {
 			metric.AZListObjectsCompleted(err)
 			return numFiles, size, err
 		}
-		for _, blobItem := range resp.ListBlobsFlatSegmentResponse.Segment.BlobItems {
+		for _, blobItem := range resp.Segment.BlobItems {
 			if blobItem.Properties != nil {
 				contentType := util.GetStringFromPointer(blobItem.Properties.ContentType)
 				isDir := checkDirectoryMarkers(contentType, blobItem.Metadata)
@@ -629,7 +629,7 @@ func (fs *AzureBlobFs) Walk(root string, walkFn filepath.WalkFunc) error {
 			metric.AZListObjectsCompleted(err)
 			return err
 		}
-		for _, blobItem := range resp.ListBlobsFlatSegmentResponse.Segment.BlobItems {
+		for _, blobItem := range resp.Segment.BlobItems {
 			name := util.GetStringFromPointer(blobItem.Name)
 			if fs.isEqual(name, prefix) {
 				continue
@@ -886,7 +886,7 @@ func (fs *AzureBlobFs) hasContents(name string) (bool, error) {
 			return result, err
 		}
 
-		result = len(resp.ListBlobsFlatSegmentResponse.Segment.BlobItems) > 0
+		result = len(resp.Segment.BlobItems) > 0
 	}
 
 	metric.AZListObjectsCompleted(nil)
@@ -909,9 +909,9 @@ func (fs *AzureBlobFs) downloadPart(ctx context.Context, blockBlob *blockblob.Cl
 	if err != nil {
 		return err
 	}
-	defer resp.DownloadResponse.Body.Close()
+	defer resp.Body.Close()
 
-	_, err = io.ReadAtLeast(resp.DownloadResponse.Body, buf, int(count))
+	_, err = io.ReadAtLeast(resp.Body, buf, int(count))
 	if err != nil {
 		return err
 	}
@@ -1280,7 +1280,7 @@ func (l *azureBlobDirLister) Next(limit int) ([]os.FileInfo, error) {
 		return l.cache, err
 	}
 
-	for _, blobPrefix := range page.ListBlobsHierarchySegmentResponse.Segment.BlobPrefixes {
+	for _, blobPrefix := range page.Segment.BlobPrefixes {
 		name := util.GetStringFromPointer(blobPrefix.Name)
 		// we don't support prefixes == "/" this will be sent if a key starts with "/"
 		if name == "" || name == "/" {
@@ -1295,7 +1295,7 @@ func (l *azureBlobDirLister) Next(limit int) ([]os.FileInfo, error) {
 		l.prefixes[strings.TrimSuffix(name, "/")] = true
 	}
 
-	for _, blobItem := range page.ListBlobsHierarchySegmentResponse.Segment.BlobItems {
+	for _, blobItem := range page.Segment.BlobItems {
 		name := util.GetStringFromPointer(blobItem.Name)
 		name = strings.TrimPrefix(name, l.prefix)
 		size := int64(0)

+ 2 - 2
internal/vfs/cryptfs.go

@@ -59,8 +59,8 @@ func NewCryptFs(connectionID, rootDir, mountPath string, config CryptFsConfig) (
 			connectionID:    connectionID,
 			rootDir:         rootDir,
 			mountPath:       getMountPath(mountPath),
-			readBufferSize:  config.OSFsConfig.ReadBufferSize * 1024 * 1024,
-			writeBufferSize: config.OSFsConfig.WriteBufferSize * 1024 * 1024,
+			readBufferSize:  config.ReadBufferSize * 1024 * 1024,
+			writeBufferSize: config.WriteBufferSize * 1024 * 1024,
 		},
 		masterKey: []byte(config.Passphrase.GetPayload()),
 	}

+ 2 - 2
internal/vfs/gcsfs.go

@@ -730,10 +730,10 @@ func (fs *GCSFs) setWriterAttrs(objectWriter *storage.Writer, flag int, name str
 		contentType = mime.TypeByExtension(path.Ext(name))
 	}
 	if contentType != "" {
-		objectWriter.ObjectAttrs.ContentType = contentType
+		objectWriter.ContentType = contentType
 	}
 	if fs.config.StorageClass != "" {
-		objectWriter.ObjectAttrs.StorageClass = fs.config.StorageClass
+		objectWriter.StorageClass = fs.config.StorageClass
 	}
 	if fs.config.ACL != "" {
 		objectWriter.PredefinedACL = fs.config.ACL

+ 7 - 6
internal/webdavd/file.go

@@ -165,7 +165,7 @@ func (f *webDavFile) checkFirstRead() error {
 	if !f.Connection.User.HasPerm(dataprovider.PermDownload, path.Dir(f.GetVirtualPath())) {
 		return f.Connection.GetPermissionDeniedError()
 	}
-	transferQuota := f.BaseTransfer.GetTransferQuota()
+	transferQuota := f.GetTransferQuota()
 	if !transferQuota.HasDownloadSpace() {
 		f.Connection.Log(logger.LevelInfo, "denying file read due to quota limits")
 		return f.Connection.GetReadQuotaExceededError()
@@ -212,7 +212,7 @@ func (f *webDavFile) Read(p []byte) (n int, err error) {
 			} else if r != nil {
 				f.reader = r
 			}
-			f.BaseTransfer.SetCancelFn(cancelFn)
+			f.SetCancelFn(cancelFn)
 		}
 		f.ErrTransfer = e
 		f.startOffset = 0
@@ -322,9 +322,10 @@ func (f *webDavFile) Seek(offset int64, whence int) (int64, error) {
 	if f.GetType() == common.TransferDownload {
 		readOffset := f.startOffset + f.BytesSent.Load()
 		if offset == 0 && readOffset == 0 {
-			if whence == io.SeekStart {
+			switch whence {
+			case io.SeekStart:
 				return 0, nil
-			} else if whence == io.SeekEnd {
+			case io.SeekEnd:
 				if err := f.updateStatInfo(); err != nil {
 					return 0, err
 				}
@@ -363,7 +364,7 @@ func (f *webDavFile) Seek(offset int64, whence int) (int64, error) {
 			f.reader = r
 		}
 		f.ErrTransfer = err
-		f.BaseTransfer.SetCancelFn(cancelFn)
+		f.SetCancelFn(cancelFn)
 		f.Unlock()
 
 		return startByte, err
@@ -403,7 +404,7 @@ func (f *webDavFile) closeIO() error {
 	} else if f.reader != nil {
 		err = f.reader.Close()
 		if metadater, ok := f.reader.(vfs.Metadater); ok {
-			f.BaseTransfer.SetMetadata(metadater.Metadata())
+			f.SetMetadata(metadater.Metadata())
 		}
 	}
 	return err