Kaynağa Gözat

portable mode: add support for file extensions filters

Nicola Murino 5 yıl önce
ebeveyn
işleme
ec8ab28a22
4 değiştirilmiş dosya ile 88 ekleme ve 18 silme
  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"
 	"io/ioutil"
 	"os"
+	"path"
 	"path/filepath"
+	"strings"
 
 	"github.com/drakkan/sftpgo/dataprovider"
 	"github.com/drakkan/sftpgo/service"
@@ -25,6 +27,8 @@ var (
 	portablePublicKeys           []string
 	portablePermissions          []string
 	portableSSHCommands          []string
+	portableAllowedExtensions    []string
+	portableDeniedExtensions     []string
 	portableFsProvider           int
 	portableS3Bucket             string
 	portableS3Region             string
@@ -113,6 +117,9 @@ Please take a look at the usage below to customize the serving parameters`,
 							KeyPrefix:            portableGCSKeyPrefix,
 						},
 					},
+					Filters: dataprovider.UserFilters{
+						FileExtensions: parseFileExtensionsFilters(),
+					},
 				},
 			}
 			if err := service.StartPortableMode(portableSFTPDPort, portableSSHCommands, portableAdvertiseService,
@@ -135,6 +142,10 @@ func init() {
 	portableCmd.Flags().StringSliceVarP(&portablePublicKeys, "public-key", "k", []string{}, "")
 	portableCmd.Flags().StringSliceVarP(&portablePermissions, "permissions", "g", []string{"list", "download"},
 		"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,
 		"Advertise SFTP service using multicast DNS")
 	portableCmd.Flags().BoolVarP(&portableAdvertiseCredentials, "advertise-credentials", "C", false,
@@ -158,3 +169,58 @@ func init() {
 		"credentials file, 1 automatic")
 	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 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

+ 18 - 15
docs/portable-mode.md

@@ -14,30 +14,33 @@ Usage:
   sftpgo portable [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-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
-  -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
       --s3-access-key string
       --s3-access-secret string
       --s3-bucket 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-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.

+ 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, "+
-		"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
 }