Просмотр исходного кода

portable mode: add support for file extensions filters

Nicola Murino 5 лет назад
Родитель
Сommit
ec8ab28a22
4 измененных файлов с 88 добавлено и 18 удалено
  1. 66 0
      cmd/portable.go
  2. 1 1
      docs/account.md
  3. 18 15
      docs/portable-mode.md
  4. 3 2
      service/service.go

+ 66 - 0
cmd/portable.go

@@ -5,7 +5,9 @@ import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
+	"path"
 	"path/filepath"
 	"path/filepath"
+	"strings"
 
 
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/service"
 	"github.com/drakkan/sftpgo/service"
@@ -25,6 +27,8 @@ var (
 	portablePublicKeys           []string
 	portablePublicKeys           []string
 	portablePermissions          []string
 	portablePermissions          []string
 	portableSSHCommands          []string
 	portableSSHCommands          []string
+	portableAllowedExtensions    []string
+	portableDeniedExtensions     []string
 	portableFsProvider           int
 	portableFsProvider           int
 	portableS3Bucket             string
 	portableS3Bucket             string
 	portableS3Region             string
 	portableS3Region             string
@@ -113,6 +117,9 @@ Please take a look at the usage below to customize the serving parameters`,
 							KeyPrefix:            portableGCSKeyPrefix,
 							KeyPrefix:            portableGCSKeyPrefix,
 						},
 						},
 					},
 					},
+					Filters: dataprovider.UserFilters{
+						FileExtensions: parseFileExtensionsFilters(),
+					},
 				},
 				},
 			}
 			}
 			if err := service.StartPortableMode(portableSFTPDPort, portableSSHCommands, portableAdvertiseService,
 			if err := service.StartPortableMode(portableSFTPDPort, portableSSHCommands, portableAdvertiseService,
@@ -135,6 +142,10 @@ func init() {
 	portableCmd.Flags().StringSliceVarP(&portablePublicKeys, "public-key", "k", []string{}, "")
 	portableCmd.Flags().StringSliceVarP(&portablePublicKeys, "public-key", "k", []string{}, "")
 	portableCmd.Flags().StringSliceVarP(&portablePermissions, "permissions", "g", []string{"list", "download"},
 	portableCmd.Flags().StringSliceVarP(&portablePermissions, "permissions", "g", []string{"list", "download"},
 		"User's permissions. \"*\" means any permission")
 		"User's permissions. \"*\" means any permission")
+	portableCmd.Flags().StringArrayVar(&portableAllowedExtensions, "allowed-extensions", []string{},
+		"Allowed file extensions case insensitive. The format is /dir::ext1,ext2. For example: \"/somedir::.jpg,.png\"")
+	portableCmd.Flags().StringArrayVar(&portableDeniedExtensions, "denied-extensions", []string{},
+		"Denied file extensions case insensitive. The format is /dir::ext1,ext2. For example: \"/somedir::.jpg,.png\"")
 	portableCmd.Flags().BoolVarP(&portableAdvertiseService, "advertise-service", "S", true,
 	portableCmd.Flags().BoolVarP(&portableAdvertiseService, "advertise-service", "S", true,
 		"Advertise SFTP service using multicast DNS")
 		"Advertise SFTP service using multicast DNS")
 	portableCmd.Flags().BoolVarP(&portableAdvertiseCredentials, "advertise-credentials", "C", false,
 	portableCmd.Flags().BoolVarP(&portableAdvertiseCredentials, "advertise-credentials", "C", false,
@@ -158,3 +169,58 @@ func init() {
 		"credentials file, 1 automatic")
 		"credentials file, 1 automatic")
 	rootCmd.AddCommand(portableCmd)
 	rootCmd.AddCommand(portableCmd)
 }
 }
+
+func parseFileExtensionsFilters() []dataprovider.ExtensionsFilter {
+	var extensions []dataprovider.ExtensionsFilter
+	for _, val := range portableAllowedExtensions {
+		p, exts := getExtensionsFilterValues(strings.TrimSpace(val))
+		if len(p) > 0 {
+			extensions = append(extensions, dataprovider.ExtensionsFilter{
+				Path:              path.Clean(p),
+				AllowedExtensions: exts,
+				DeniedExtensions:  []string{},
+			})
+		}
+	}
+	for _, val := range portableDeniedExtensions {
+		p, exts := getExtensionsFilterValues(strings.TrimSpace(val))
+		if len(p) > 0 {
+			found := false
+			for index, e := range extensions {
+				if path.Clean(e.Path) == path.Clean(p) {
+					extensions[index].DeniedExtensions = append(extensions[index].DeniedExtensions, exts...)
+					found = true
+					break
+				}
+			}
+			if !found {
+				extensions = append(extensions, dataprovider.ExtensionsFilter{
+					Path:              path.Clean(p),
+					AllowedExtensions: []string{},
+					DeniedExtensions:  exts,
+				})
+			}
+		}
+	}
+	return extensions
+}
+
+func getExtensionsFilterValues(value string) (string, []string) {
+	if strings.Contains(value, "::") {
+		dirExts := strings.Split(value, "::")
+		if len(dirExts) > 1 {
+			dir := strings.TrimSpace(dirExts[0])
+			exts := []string{}
+			for _, e := range strings.Split(dirExts[1], ",") {
+				cleanedExt := strings.TrimSpace(e)
+				if len(cleanedExt) > 0 {
+					exts = append(exts, cleanedExt)
+				}
+			}
+			if len(dir) > 0 && len(exts) > 0 {
+				return dir, exts
+			}
+		}
+	}
+	return "", nil
+}

+ 1 - 1
docs/account.md

@@ -57,5 +57,5 @@ These properties are stored inside the data provider.
 If you want to use your existing accounts, you have these options:
 If you want to use your existing accounts, you have these options:
 
 
 - If your accounts are aleady stored inside a supported database, you can create a database view. Since a view is read only, you have to disable user management and quota tracking so SFTPGo will never try to write to the view
 - If your accounts are aleady stored inside a supported database, you can create a database view. Since a view is read only, you have to disable user management and quota tracking so SFTPGo will never try to write to the view
-- you can import your users inside SFTPGo. Take a look at [sftpgo_api_cli.py](../scripts/README.md "SFTPGo api cli script"), it can convert and import users from Linux system users and Pure-FTPd/ProFTPD virtual users
+- you can import your users inside SFTPGo. Take a look at [sftpgo_api_cli.py](../scripts#convert-users-from-other-stores "SFTPGo API CLI script"), it can convert and import users from Linux system users and Pure-FTPd/ProFTPD virtual users
 - you can use an external authentication program
 - you can use an external authentication program

+ 18 - 15
docs/portable-mode.md

@@ -14,30 +14,33 @@ Usage:
   sftpgo portable [flags]
   sftpgo portable [flags]
 
 
 Flags:
 Flags:
-  -C, --advertise-credentials           If the SFTP service is advertised via multicast DNS, this flag allows to put username/password inside the advertised TXT record
-  -S, --advertise-service               Advertise SFTP service using multicast DNS (default true)
-  -d, --directory string                Path to the directory to serve. This can be an absolute path or a path relative to the current directory (default ".")
-  -f, --fs-provider int                 0 means local filesystem, 1 Amazon S3 compatible, 2 Google Cloud Storage
-      --gcs-automatic-credentials int   0 means explicit credentials using a JSON credentials file, 1 automatic (default 1)
+  -C, --advertise-credentials            If the SFTP service is advertised via multicast DNS, this flag allows to put username/password inside the advertised TXT record
+  -S, --advertise-service                Advertise SFTP service using multicast DNS (default true)
+      --allowed-extensions stringArray   Allowed file extensions case insensitive. The format is /dir::ext1,ext2. For example: "/somedir::.jpg,.png"
+      --denied-extensions stringArray    Denied file extensions case insensitive. The format is /dir::ext1,ext2. For example: "/somedir::.jpg,.png"
+  -d, --directory string                 Path to the directory to serve. This can be an absolute path or a path relative to the current directory (default ".")
+  -f, --fs-provider int                  0 means local filesystem, 1 Amazon S3 compatible, 2 Google Cloud Storage
+      --gcs-automatic-credentials int    0 means explicit credentials using a JSON credentials file, 1 automatic (default 1)
       --gcs-bucket string
       --gcs-bucket string
-      --gcs-credentials-file string     Google Cloud Storage JSON credentials file
-      --gcs-key-prefix string           Allows to restrict access to the virtual folder identified by this prefix and its contents
+      --gcs-credentials-file string      Google Cloud Storage JSON credentials file
+      --gcs-key-prefix string            Allows to restrict access to the virtual folder identified by this prefix and its contents
       --gcs-storage-class string
       --gcs-storage-class string
-  -h, --help                            help for portable
-  -l, --log-file-path string            Leave empty to disable logging
-  -p, --password string                 Leave empty to use an auto generated value
-  -g, --permissions strings             User's permissions. "*" means any permission (default [list,download])
+  -h, --help                             help for portable
+  -l, --log-file-path string             Leave empty to disable logging
+  -p, --password string                  Leave empty to use an auto generated value
+  -g, --permissions strings              User's permissions. "*" means any permission (default [list,download])
   -k, --public-key strings
   -k, --public-key strings
       --s3-access-key string
       --s3-access-key string
       --s3-access-secret string
       --s3-access-secret string
       --s3-bucket string
       --s3-bucket string
       --s3-endpoint string
       --s3-endpoint string
-      --s3-key-prefix string            Allows to restrict access to the virtual folder identified by this prefix and its contents
+      --s3-key-prefix string             Allows to restrict access to the virtual folder identified by this prefix and its contents
       --s3-region string
       --s3-region string
       --s3-storage-class string
       --s3-storage-class string
-  -s, --sftpd-port int                  0 means a random non privileged port
-  -c, --ssh-commands strings            SSH commands to enable. "*" means any supported SSH command including scp (default [md5sum,sha1sum,cd,pwd])
-  -u, --username string                 Leave empty to use an auto generated value
+  -s, --sftpd-port int                   0 means a random non privileged port
+  -c, --ssh-commands strings             SSH commands to enable. "*" means any supported SSH command including scp (default [md5sum,sha1sum,cd,pwd])
+  -u, --username string                  Leave empty to use an auto generated value
+
 ```
 ```
 
 
 In portable mode, SFTPGo can advertise the SFTP service and, optionally, the credentials via multicast DNS, so there is a standard way to discover the service and to automatically connect to it.
 In portable mode, SFTPGo can advertise the SFTP service and, optionally, the credentials via multicast DNS, so there is a standard way to discover the service and to automatically connect to it.

+ 3 - 2
service/service.go

@@ -221,8 +221,9 @@ func (s *Service) StartPortableMode(sftpdPort int, enabledSSHCommands []string,
 	}()
 	}()
 
 
 	logger.InfoToConsole("Portable mode ready, SFTP port: %v, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
 	logger.InfoToConsole("Portable mode ready, SFTP port: %v, user: %#v, password: %#v, public keys: %v, directory: %#v, "+
-		"permissions: %v, enabled ssh commands: %v", sftpdConf.BindPort, s.PortableUser.Username, s.PortableUser.Password,
-		s.PortableUser.PublicKeys, s.getPortableDirToServe(), s.PortableUser.Permissions, sftpdConf.EnabledSSHCommands)
+		"permissions: %+v, enabled ssh commands: %v file extensions filters: %+v", sftpdConf.BindPort, s.PortableUser.Username,
+		s.PortableUser.Password, s.PortableUser.PublicKeys, s.getPortableDirToServe(), s.PortableUser.Permissions,
+		sftpdConf.EnabledSSHCommands, s.PortableUser.Filters.FileExtensions)
 	return nil
 	return nil
 }
 }