mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-22 07:30:25 +00:00
trim values for string lists which can be set as env vars
See #857 Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
parent
7329cd804b
commit
cc2f23bd89
20 changed files with 74 additions and 49 deletions
|
@ -26,7 +26,7 @@ RUN set -xe && \
|
||||||
go build $(if [ -n "${FEATURES}" ]; then echo "-tags ${FEATURES}"; fi) -trimpath -ldflags "-s -w -X github.com/drakkan/sftpgo/v2/version.commit=${COMMIT_SHA} -X github.com/drakkan/sftpgo/v2/version.date=`date -u +%FT%TZ`" -v -o sftpgo
|
go build $(if [ -n "${FEATURES}" ]; then echo "-tags ${FEATURES}"; fi) -trimpath -ldflags "-s -w -X github.com/drakkan/sftpgo/v2/version.commit=${COMMIT_SHA} -X github.com/drakkan/sftpgo/v2/version.date=`date -u +%FT%TZ`" -v -o sftpgo
|
||||||
|
|
||||||
|
|
||||||
FROM alpine:3.15
|
FROM alpine:3.16
|
||||||
|
|
||||||
# Set to "true" to install jq and the optional git and rsync dependencies
|
# Set to "true" to install jq and the optional git and rsync dependencies
|
||||||
ARG INSTALL_OPTIONAL_PACKAGES=false
|
ARG INSTALL_OPTIONAL_PACKAGES=false
|
||||||
|
|
|
@ -216,7 +216,7 @@ func (c *Configuration) checkDomains() {
|
||||||
domains = append(domains, d)
|
domains = append(domains, d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.Domains = util.RemoveDuplicates(domains)
|
c.Domains = util.RemoveDuplicates(domains, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) setLockTime() error {
|
func (c *Configuration) setLockTime() error {
|
||||||
|
|
|
@ -141,6 +141,9 @@ var (
|
||||||
// Initialize sets the common configuration
|
// Initialize sets the common configuration
|
||||||
func Initialize(c Configuration, isShared int) error {
|
func Initialize(c Configuration, isShared int) error {
|
||||||
Config = c
|
Config = c
|
||||||
|
Config.Actions.ExecuteOn = util.RemoveDuplicates(Config.Actions.ExecuteOn, true)
|
||||||
|
Config.Actions.ExecuteSync = util.RemoveDuplicates(Config.Actions.ExecuteSync, true)
|
||||||
|
Config.ProxyAllowed = util.RemoveDuplicates(Config.ProxyAllowed, true)
|
||||||
Config.idleLoginTimeout = 2 * time.Minute
|
Config.idleLoginTimeout = 2 * time.Minute
|
||||||
Config.idleTimeoutAsDuration = time.Duration(Config.IdleTimeout) * time.Minute
|
Config.idleTimeoutAsDuration = time.Duration(Config.IdleTimeout) * time.Minute
|
||||||
startPeriodicTimeoutTicker(periodicTimeoutCheckInterval)
|
startPeriodicTimeoutTicker(periodicTimeoutCheckInterval)
|
||||||
|
|
|
@ -299,6 +299,7 @@ func addEntriesToList(entries []string, hostList *HostList, listName string) *Ho
|
||||||
cdrLoaded := 0
|
cdrLoaded := 0
|
||||||
|
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
|
entry = strings.TrimSpace(entry)
|
||||||
if strings.LastIndex(entry, "/") > 0 {
|
if strings.LastIndex(entry, "/") > 0 {
|
||||||
cdrCount++
|
cdrCount++
|
||||||
_, network, err := net.ParseCIDR(entry)
|
_, network, err := net.ParseCIDR(entry)
|
||||||
|
|
|
@ -81,7 +81,7 @@ func (r *RateLimiterConfig) validate() error {
|
||||||
return fmt.Errorf("invalid entries_hard_limit %v must be > %v", r.EntriesHardLimit, r.EntriesSoftLimit)
|
return fmt.Errorf("invalid entries_hard_limit %v must be > %v", r.EntriesHardLimit, r.EntriesSoftLimit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.Protocols = util.RemoveDuplicates(r.Protocols)
|
r.Protocols = util.RemoveDuplicates(r.Protocols, true)
|
||||||
for _, protocol := range r.Protocols {
|
for _, protocol := range r.Protocols {
|
||||||
if !util.Contains(rateLimiterProtocolValues, protocol) {
|
if !util.Contains(rateLimiterProtocolValues, protocol) {
|
||||||
return fmt.Errorf("invalid protocol %#v", protocol)
|
return fmt.Errorf("invalid protocol %#v", protocol)
|
||||||
|
|
|
@ -204,13 +204,13 @@ func (m *CertManager) LoadRootCAs() error {
|
||||||
// SetCACertificates sets the root CA authorities file paths.
|
// SetCACertificates sets the root CA authorities file paths.
|
||||||
// This should not be changed at runtime
|
// This should not be changed at runtime
|
||||||
func (m *CertManager) SetCACertificates(caCertificates []string) {
|
func (m *CertManager) SetCACertificates(caCertificates []string) {
|
||||||
m.caCertificates = caCertificates
|
m.caCertificates = util.RemoveDuplicates(caCertificates, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCARevocationLists sets the CA revocation lists file paths.
|
// SetCARevocationLists sets the CA revocation lists file paths.
|
||||||
// This should not be changed at runtime
|
// This should not be changed at runtime
|
||||||
func (m *CertManager) SetCARevocationLists(caRevocationLists []string) {
|
func (m *CertManager) SetCARevocationLists(caRevocationLists []string) {
|
||||||
m.caRevocationLists = caRevocationLists
|
m.caRevocationLists = util.RemoveDuplicates(caRevocationLists, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCertManager creates a new certificate manager
|
// NewCertManager creates a new certificate manager
|
||||||
|
|
|
@ -176,7 +176,7 @@ func (a *Admin) validateRecoveryCodes() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Admin) validatePermissions() error {
|
func (a *Admin) validatePermissions() error {
|
||||||
a.Permissions = util.RemoveDuplicates(a.Permissions)
|
a.Permissions = util.RemoveDuplicates(a.Permissions, false)
|
||||||
if len(a.Permissions) == 0 {
|
if len(a.Permissions) == 0 {
|
||||||
return util.NewValidationError("please grant some permissions to this admin")
|
return util.NewValidationError("please grant some permissions to this admin")
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ func (a *Admin) validate() error {
|
||||||
if a.Email != "" && !util.IsEmailValid(a.Email) {
|
if a.Email != "" && !util.IsEmailValid(a.Email) {
|
||||||
return util.NewValidationError(fmt.Sprintf("email %#v is not valid", a.Email))
|
return util.NewValidationError(fmt.Sprintf("email %#v is not valid", a.Email))
|
||||||
}
|
}
|
||||||
a.Filters.AllowList = util.RemoveDuplicates(a.Filters.AllowList)
|
a.Filters.AllowList = util.RemoveDuplicates(a.Filters.AllowList, false)
|
||||||
for _, IPMask := range a.Filters.AllowList {
|
for _, IPMask := range a.Filters.AllowList {
|
||||||
_, _, err := net.ParseCIDR(IPMask)
|
_, _, err := net.ParseCIDR(IPMask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -712,6 +712,8 @@ func SetTempPath(fsPath string) {
|
||||||
func Initialize(cnf Config, basePath string, checkAdmins bool) error {
|
func Initialize(cnf Config, basePath string, checkAdmins bool) error {
|
||||||
var err error
|
var err error
|
||||||
config = cnf
|
config = cnf
|
||||||
|
config.Actions.ExecuteOn = util.RemoveDuplicates(config.Actions.ExecuteOn, true)
|
||||||
|
config.Actions.ExecuteFor = util.RemoveDuplicates(config.Actions.ExecuteFor, true)
|
||||||
|
|
||||||
cnf.BackupsPath = getConfigPath(cnf.BackupsPath, basePath)
|
cnf.BackupsPath = getConfigPath(cnf.BackupsPath, basePath)
|
||||||
if cnf.BackupsPath == "" {
|
if cnf.BackupsPath == "" {
|
||||||
|
@ -1736,7 +1738,7 @@ func UpdateFolder(folder *vfs.BaseVirtualFolder, users []string, groups []string
|
||||||
usersInGroups, errGrp := provider.getUsersInGroups(groups)
|
usersInGroups, errGrp := provider.getUsersInGroups(groups)
|
||||||
if errGrp == nil {
|
if errGrp == nil {
|
||||||
users = append(users, usersInGroups...)
|
users = append(users, usersInGroups...)
|
||||||
users = util.RemoveDuplicates(users)
|
users = util.RemoveDuplicates(users, false)
|
||||||
} else {
|
} else {
|
||||||
providerLog(logger.LevelWarn, "unable to get users in groups %+v: %v", groups, errGrp)
|
providerLog(logger.LevelWarn, "unable to get users in groups %+v: %v", groups, errGrp)
|
||||||
}
|
}
|
||||||
|
@ -1767,7 +1769,7 @@ func DeleteFolder(folderName, executor, ipAddress string) error {
|
||||||
usersInGroups, errGrp := provider.getUsersInGroups(folder.Groups)
|
usersInGroups, errGrp := provider.getUsersInGroups(folder.Groups)
|
||||||
if errGrp == nil {
|
if errGrp == nil {
|
||||||
users = append(users, usersInGroups...)
|
users = append(users, usersInGroups...)
|
||||||
users = util.RemoveDuplicates(users)
|
users = util.RemoveDuplicates(users, false)
|
||||||
} else {
|
} else {
|
||||||
providerLog(logger.LevelWarn, "unable to get users in groups %+v: %v", folder.Groups, errGrp)
|
providerLog(logger.LevelWarn, "unable to get users in groups %+v: %v", folder.Groups, errGrp)
|
||||||
}
|
}
|
||||||
|
@ -2156,7 +2158,7 @@ func validateUserPermissions(permsToCheck map[string][]string) (map[string][]str
|
||||||
if util.Contains(perms, PermAny) {
|
if util.Contains(perms, PermAny) {
|
||||||
permissions[cleanedDir] = []string{PermAny}
|
permissions[cleanedDir] = []string{PermAny}
|
||||||
} else {
|
} else {
|
||||||
permissions[cleanedDir] = util.RemoveDuplicates(perms)
|
permissions[cleanedDir] = util.RemoveDuplicates(perms, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2193,7 +2195,7 @@ func validatePublicKeys(user *User) error {
|
||||||
}
|
}
|
||||||
validatedKeys = append(validatedKeys, k)
|
validatedKeys = append(validatedKeys, k)
|
||||||
}
|
}
|
||||||
user.PublicKeys = util.RemoveDuplicates(validatedKeys)
|
user.PublicKeys = util.RemoveDuplicates(validatedKeys, false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2235,8 +2237,8 @@ func validateFiltersPatternExtensions(baseFilters *sdk.BaseUserFilters) error {
|
||||||
}
|
}
|
||||||
denied = append(denied, strings.ToLower(pattern))
|
denied = append(denied, strings.ToLower(pattern))
|
||||||
}
|
}
|
||||||
f.AllowedPatterns = util.RemoveDuplicates(allowed)
|
f.AllowedPatterns = util.RemoveDuplicates(allowed, false)
|
||||||
f.DeniedPatterns = util.RemoveDuplicates(denied)
|
f.DeniedPatterns = util.RemoveDuplicates(denied, false)
|
||||||
filters = append(filters, f)
|
filters = append(filters, f)
|
||||||
filteredPaths = append(filteredPaths, cleanedPath)
|
filteredPaths = append(filteredPaths, cleanedPath)
|
||||||
}
|
}
|
||||||
|
@ -2260,14 +2262,14 @@ func checkEmptyFiltersStruct(filters *sdk.BaseUserFilters) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateIPFilters(filters *sdk.BaseUserFilters) error {
|
func validateIPFilters(filters *sdk.BaseUserFilters) error {
|
||||||
filters.DeniedIP = util.RemoveDuplicates(filters.DeniedIP)
|
filters.DeniedIP = util.RemoveDuplicates(filters.DeniedIP, false)
|
||||||
for _, IPMask := range filters.DeniedIP {
|
for _, IPMask := range filters.DeniedIP {
|
||||||
_, _, err := net.ParseCIDR(IPMask)
|
_, _, err := net.ParseCIDR(IPMask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return util.NewValidationError(fmt.Sprintf("could not parse denied IP/Mask %#v: %v", IPMask, err))
|
return util.NewValidationError(fmt.Sprintf("could not parse denied IP/Mask %#v: %v", IPMask, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
filters.AllowedIP = util.RemoveDuplicates(filters.AllowedIP)
|
filters.AllowedIP = util.RemoveDuplicates(filters.AllowedIP, false)
|
||||||
for _, IPMask := range filters.AllowedIP {
|
for _, IPMask := range filters.AllowedIP {
|
||||||
_, _, err := net.ParseCIDR(IPMask)
|
_, _, err := net.ParseCIDR(IPMask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -2307,7 +2309,7 @@ func validateBandwidthLimitsFilter(filters *sdk.BaseUserFilters) error {
|
||||||
|
|
||||||
func validateTransferLimitsFilter(filters *sdk.BaseUserFilters) error {
|
func validateTransferLimitsFilter(filters *sdk.BaseUserFilters) error {
|
||||||
for idx, limit := range filters.DataTransferLimits {
|
for idx, limit := range filters.DataTransferLimits {
|
||||||
filters.DataTransferLimits[idx].Sources = util.RemoveDuplicates(limit.Sources)
|
filters.DataTransferLimits[idx].Sources = util.RemoveDuplicates(limit.Sources, false)
|
||||||
if len(limit.Sources) == 0 {
|
if len(limit.Sources) == 0 {
|
||||||
return util.NewValidationError("no data transfer limit source specified")
|
return util.NewValidationError("no data transfer limit source specified")
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,7 +196,7 @@ func (s *Share) validatePaths() error {
|
||||||
for idx := range s.Paths {
|
for idx := range s.Paths {
|
||||||
s.Paths[idx] = util.CleanPath(s.Paths[idx])
|
s.Paths[idx] = util.CleanPath(s.Paths[idx])
|
||||||
}
|
}
|
||||||
s.Paths = util.RemoveDuplicates(s.Paths)
|
s.Paths = util.RemoveDuplicates(s.Paths, false)
|
||||||
if s.Scope >= ShareScopeWrite && len(s.Paths) != 1 {
|
if s.Scope >= ShareScopeWrite && len(s.Paths) != 1 {
|
||||||
return util.NewValidationError("the write share scope requires exactly one path")
|
return util.NewValidationError("the write share scope requires exactly one path")
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,7 @@ func (s *Share) validate() error {
|
||||||
if err := s.hashPassword(); err != nil {
|
if err := s.hashPassword(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.AllowFrom = util.RemoveDuplicates(s.AllowFrom)
|
s.AllowFrom = util.RemoveDuplicates(s.AllowFrom, false)
|
||||||
for _, IPMask := range s.AllowFrom {
|
for _, IPMask := range s.AllowFrom {
|
||||||
_, _, err := net.ParseCIDR(IPMask)
|
_, _, err := net.ParseCIDR(IPMask)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1301,7 +1301,7 @@ func sqlCommonGetRecentlyUpdatedUsers(after int64, dbHandle sqlQuerier) ([]User,
|
||||||
groupNames = append(groupNames, g.Name)
|
groupNames = append(groupNames, g.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupNames = util.RemoveDuplicates(groupNames)
|
groupNames = util.RemoveDuplicates(groupNames, false)
|
||||||
groups, err := sqlCommonGetGroupsWithNames(groupNames, dbHandle)
|
groups, err := sqlCommonGetGroupsWithNames(groupNames, dbHandle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return users, err
|
return users, err
|
||||||
|
@ -1372,7 +1372,7 @@ func sqlCommonGetUsersForQuotaCheck(toFetch map[string]bool, dbHandle sqlQuerier
|
||||||
groupNames = append(groupNames, g.Name)
|
groupNames = append(groupNames, g.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
groupNames = util.RemoveDuplicates(groupNames)
|
groupNames = util.RemoveDuplicates(groupNames, false)
|
||||||
if len(groupNames) == 0 {
|
if len(groupNames) == 0 {
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1728,12 +1728,12 @@ func (u *User) mergeFilePatterns(group Group, groupType int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) removeDuplicatesAfterGroupMerge() {
|
func (u *User) removeDuplicatesAfterGroupMerge() {
|
||||||
u.Filters.AllowedIP = util.RemoveDuplicates(u.Filters.AllowedIP)
|
u.Filters.AllowedIP = util.RemoveDuplicates(u.Filters.AllowedIP, false)
|
||||||
u.Filters.DeniedIP = util.RemoveDuplicates(u.Filters.DeniedIP)
|
u.Filters.DeniedIP = util.RemoveDuplicates(u.Filters.DeniedIP, false)
|
||||||
u.Filters.DeniedLoginMethods = util.RemoveDuplicates(u.Filters.DeniedLoginMethods)
|
u.Filters.DeniedLoginMethods = util.RemoveDuplicates(u.Filters.DeniedLoginMethods, false)
|
||||||
u.Filters.DeniedProtocols = util.RemoveDuplicates(u.Filters.DeniedProtocols)
|
u.Filters.DeniedProtocols = util.RemoveDuplicates(u.Filters.DeniedProtocols, false)
|
||||||
u.Filters.WebClient = util.RemoveDuplicates(u.Filters.WebClient)
|
u.Filters.WebClient = util.RemoveDuplicates(u.Filters.WebClient, false)
|
||||||
u.Filters.TwoFactorAuthProtocols = util.RemoveDuplicates(u.Filters.TwoFactorAuthProtocols)
|
u.Filters.TwoFactorAuthProtocols = util.RemoveDuplicates(u.Filters.TwoFactorAuthProtocols, false)
|
||||||
u.SetEmptySecretsIfNil()
|
u.SetEmptySecretsIfNil()
|
||||||
u.groupSettingsApplied = true
|
u.groupSettingsApplied = true
|
||||||
}
|
}
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -154,10 +154,10 @@ require (
|
||||||
golang.org/x/tools v0.1.10 // indirect
|
golang.org/x/tools v0.1.10 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 // indirect
|
google.golang.org/genproto v0.0.0-20220531134929-86cf59382f1b // indirect
|
||||||
google.golang.org/grpc v1.46.2 // indirect
|
google.golang.org/grpc v1.46.2 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.66.5 // indirect
|
gopkg.in/ini.v1 v1.66.6 // indirect
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -1200,8 +1200,8 @@ google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP
|
||||||
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||||
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58 h1:a221mAAEAzq4Lz6ZWRkcS8ptb2mxoxYSt4N68aRyQHM=
|
google.golang.org/genproto v0.0.0-20220531134929-86cf59382f1b h1:X+VXcq/YthmZqFvppQm4Wleg4o//OmY2uttDv1vDvRo=
|
||||||
google.golang.org/genproto v0.0.0-20220527130721-00d5c0f3be58/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
|
google.golang.org/genproto v0.0.0-20220531134929-86cf59382f1b/go.mod h1:yKyY4AMRwFiC8yMMNaMi+RkCnjZJt9LoWuvhXjMs+To=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
@ -1257,8 +1257,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||||
gopkg.in/ini.v1 v1.66.5 h1:zfiCO0p88Fj4f6NR6KR5WdGMQ02U8vlDnN6HuD2xv5o=
|
gopkg.in/ini.v1 v1.66.6 h1:LATuAqN/shcYAOkv3wl2L4rkaKqkcgTBQjOyYDvcPKI=
|
||||||
gopkg.in/ini.v1 v1.66.5/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||||
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
|
|
|
@ -374,7 +374,7 @@ func getUserFilesAsZipStream(w http.ResponseWriter, r *http.Request) {
|
||||||
filesList[idx] = util.CleanPath(filesList[idx])
|
filesList[idx] = util.CleanPath(filesList[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
filesList = util.RemoveDuplicates(filesList)
|
filesList = util.RemoveDuplicates(filesList, false)
|
||||||
|
|
||||||
w.Header().Set("Content-Disposition", "attachment; filename=\"sftpgo-download.zip\"")
|
w.Header().Set("Content-Disposition", "attachment; filename=\"sftpgo-download.zip\"")
|
||||||
renderCompressedFiles(w, connection, baseDir, filesList, nil)
|
renderCompressedFiles(w, connection, baseDir, filesList, nil)
|
||||||
|
|
|
@ -131,7 +131,7 @@ func getCommaSeparatedQueryParam(r *http.Request, key string) []string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return util.RemoveDuplicates(result)
|
return util.RemoveDuplicates(result, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBoolQueryParam(r *http.Request, param string) bool {
|
func getBoolQueryParam(r *http.Request, param string) bool {
|
||||||
|
|
|
@ -1112,10 +1112,10 @@ func (s *httpdServer) initializeRouter() {
|
||||||
}
|
}
|
||||||
if s.cors.Enabled {
|
if s.cors.Enabled {
|
||||||
c := cors.New(cors.Options{
|
c := cors.New(cors.Options{
|
||||||
AllowedOrigins: s.cors.AllowedOrigins,
|
AllowedOrigins: util.RemoveDuplicates(s.cors.AllowedOrigins, true),
|
||||||
AllowedMethods: s.cors.AllowedMethods,
|
AllowedMethods: util.RemoveDuplicates(s.cors.AllowedMethods, true),
|
||||||
AllowedHeaders: s.cors.AllowedHeaders,
|
AllowedHeaders: util.RemoveDuplicates(s.cors.AllowedHeaders, true),
|
||||||
ExposedHeaders: s.cors.ExposedHeaders,
|
ExposedHeaders: util.RemoveDuplicates(s.cors.ExposedHeaders, true),
|
||||||
MaxAge: s.cors.MaxAge,
|
MaxAge: s.cors.MaxAge,
|
||||||
AllowCredentials: s.cors.AllowCredentials,
|
AllowCredentials: s.cors.AllowCredentials,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1886,6 +1886,17 @@ func TestSupportedSecurityOptions(t *testing.T) {
|
||||||
c.KexAlgorithms = append(c.KexAlgorithms, "not a kex")
|
c.KexAlgorithms = append(c.KexAlgorithms, "not a kex")
|
||||||
err = c.configureSecurityOptions(serverConfig)
|
err = c.configureSecurityOptions(serverConfig)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
c.KexAlgorithms = supportedKexAlgos
|
||||||
|
c.MACs = []string{
|
||||||
|
" hmac-sha2-256-etm@openssh.com ", "hmac-sha2-256",
|
||||||
|
" hmac-sha2-512-etm@openssh.com", "hmac-sha2-512 ",
|
||||||
|
"hmac-sha1 ", " hmac-sha1-96",
|
||||||
|
}
|
||||||
|
err = c.configureSecurityOptions(serverConfig)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, supportedCiphers, serverConfig.Ciphers)
|
||||||
|
assert.Equal(t, supportedMACs, serverConfig.MACs)
|
||||||
|
assert.Equal(t, supportedKexAlgos, serverConfig.KeyExchanges)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadHostKeys(t *testing.T) {
|
func TestLoadHostKeys(t *testing.T) {
|
||||||
|
|
|
@ -249,7 +249,7 @@ func (c *Configuration) getServerConfig() *ssh.ServerConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) updateSupportedAuthentications() {
|
func (c *Configuration) updateSupportedAuthentications() {
|
||||||
serviceStatus.Authentications = util.RemoveDuplicates(serviceStatus.Authentications)
|
serviceStatus.Authentications = util.RemoveDuplicates(serviceStatus.Authentications, false)
|
||||||
|
|
||||||
if util.Contains(serviceStatus.Authentications, dataprovider.LoginMethodPassword) &&
|
if util.Contains(serviceStatus.Authentications, dataprovider.LoginMethodPassword) &&
|
||||||
util.Contains(serviceStatus.Authentications, dataprovider.SSHLoginMethodPublicKey) {
|
util.Contains(serviceStatus.Authentications, dataprovider.SSHLoginMethodPublicKey) {
|
||||||
|
@ -364,7 +364,7 @@ func (c *Configuration) configureSecurityOptions(serverConfig *ssh.ServerConfig)
|
||||||
if len(c.HostKeyAlgorithms) == 0 {
|
if len(c.HostKeyAlgorithms) == 0 {
|
||||||
c.HostKeyAlgorithms = preferredHostKeyAlgos
|
c.HostKeyAlgorithms = preferredHostKeyAlgos
|
||||||
} else {
|
} else {
|
||||||
c.HostKeyAlgorithms = util.RemoveDuplicates(c.HostKeyAlgorithms)
|
c.HostKeyAlgorithms = util.RemoveDuplicates(c.HostKeyAlgorithms, true)
|
||||||
}
|
}
|
||||||
for _, hostKeyAlgo := range c.HostKeyAlgorithms {
|
for _, hostKeyAlgo := range c.HostKeyAlgorithms {
|
||||||
if !util.Contains(supportedHostKeyAlgos, hostKeyAlgo) {
|
if !util.Contains(supportedHostKeyAlgos, hostKeyAlgo) {
|
||||||
|
@ -374,7 +374,7 @@ func (c *Configuration) configureSecurityOptions(serverConfig *ssh.ServerConfig)
|
||||||
serverConfig.HostKeyAlgorithms = c.HostKeyAlgorithms
|
serverConfig.HostKeyAlgorithms = c.HostKeyAlgorithms
|
||||||
|
|
||||||
if len(c.KexAlgorithms) > 0 {
|
if len(c.KexAlgorithms) > 0 {
|
||||||
c.KexAlgorithms = util.RemoveDuplicates(c.KexAlgorithms)
|
c.KexAlgorithms = util.RemoveDuplicates(c.KexAlgorithms, true)
|
||||||
for _, kex := range c.KexAlgorithms {
|
for _, kex := range c.KexAlgorithms {
|
||||||
if !util.Contains(supportedKexAlgos, kex) {
|
if !util.Contains(supportedKexAlgos, kex) {
|
||||||
return fmt.Errorf("unsupported key-exchange algorithm %#v", kex)
|
return fmt.Errorf("unsupported key-exchange algorithm %#v", kex)
|
||||||
|
@ -383,7 +383,7 @@ func (c *Configuration) configureSecurityOptions(serverConfig *ssh.ServerConfig)
|
||||||
serverConfig.KeyExchanges = c.KexAlgorithms
|
serverConfig.KeyExchanges = c.KexAlgorithms
|
||||||
}
|
}
|
||||||
if len(c.Ciphers) > 0 {
|
if len(c.Ciphers) > 0 {
|
||||||
c.Ciphers = util.RemoveDuplicates(c.Ciphers)
|
c.Ciphers = util.RemoveDuplicates(c.Ciphers, true)
|
||||||
for _, cipher := range c.Ciphers {
|
for _, cipher := range c.Ciphers {
|
||||||
if !util.Contains(supportedCiphers, cipher) {
|
if !util.Contains(supportedCiphers, cipher) {
|
||||||
return fmt.Errorf("unsupported cipher %#v", cipher)
|
return fmt.Errorf("unsupported cipher %#v", cipher)
|
||||||
|
@ -392,7 +392,7 @@ func (c *Configuration) configureSecurityOptions(serverConfig *ssh.ServerConfig)
|
||||||
serverConfig.Ciphers = c.Ciphers
|
serverConfig.Ciphers = c.Ciphers
|
||||||
}
|
}
|
||||||
if len(c.MACs) > 0 {
|
if len(c.MACs) > 0 {
|
||||||
c.MACs = util.RemoveDuplicates(c.MACs)
|
c.MACs = util.RemoveDuplicates(c.MACs, true)
|
||||||
for _, mac := range c.MACs {
|
for _, mac := range c.MACs {
|
||||||
if !util.Contains(supportedMACs, mac) {
|
if !util.Contains(supportedMACs, mac) {
|
||||||
return fmt.Errorf("unsupported MAC algorithm %#v", mac)
|
return fmt.Errorf("unsupported MAC algorithm %#v", mac)
|
||||||
|
@ -727,6 +727,7 @@ func (c *Configuration) checkSSHCommands() {
|
||||||
}
|
}
|
||||||
sshCommands := []string{}
|
sshCommands := []string{}
|
||||||
for _, command := range c.EnabledSSHCommands {
|
for _, command := range c.EnabledSSHCommands {
|
||||||
|
command = strings.TrimSpace(command)
|
||||||
if util.Contains(supportedSSHCommands, command) {
|
if util.Contains(supportedSSHCommands, command) {
|
||||||
sshCommands = append(sshCommands, command)
|
sshCommands = append(sshCommands, command)
|
||||||
} else {
|
} else {
|
||||||
|
@ -780,6 +781,7 @@ func (c *Configuration) generateDefaultHostKeys(configDir string) error {
|
||||||
|
|
||||||
func (c *Configuration) checkHostKeyAutoGeneration(configDir string) error {
|
func (c *Configuration) checkHostKeyAutoGeneration(configDir string) error {
|
||||||
for _, k := range c.HostKeys {
|
for _, k := range c.HostKeys {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
if filepath.IsAbs(k) {
|
if filepath.IsAbs(k) {
|
||||||
if _, err := os.Stat(k); errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(k); errors.Is(err, fs.ErrNotExist) {
|
||||||
keyName := filepath.Base(k)
|
keyName := filepath.Base(k)
|
||||||
|
@ -837,6 +839,7 @@ func (c *Configuration) checkAndLoadHostKeys(configDir string, serverConfig *ssh
|
||||||
}
|
}
|
||||||
serviceStatus.HostKeys = nil
|
serviceStatus.HostKeys = nil
|
||||||
for _, hostKey := range c.HostKeys {
|
for _, hostKey := range c.HostKeys {
|
||||||
|
hostKey = strings.TrimSpace(hostKey)
|
||||||
if !util.IsFileInputValid(hostKey) {
|
if !util.IsFileInputValid(hostKey) {
|
||||||
logger.Warn(logSender, "", "unable to load invalid host key %#v", hostKey)
|
logger.Warn(logSender, "", "unable to load invalid host key %#v", hostKey)
|
||||||
logger.WarnToConsole("unable to load invalid host key %#v", hostKey)
|
logger.WarnToConsole("unable to load invalid host key %#v", hostKey)
|
||||||
|
@ -887,6 +890,7 @@ func (c *Configuration) checkAndLoadHostKeys(configDir string, serverConfig *ssh
|
||||||
func (c *Configuration) loadHostCertificates(configDir string) ([]*ssh.Certificate, error) {
|
func (c *Configuration) loadHostCertificates(configDir string) ([]*ssh.Certificate, error) {
|
||||||
var certs []*ssh.Certificate
|
var certs []*ssh.Certificate
|
||||||
for _, certPath := range c.HostCertificates {
|
for _, certPath := range c.HostCertificates {
|
||||||
|
certPath = strings.TrimSpace(certPath)
|
||||||
if !util.IsFileInputValid(certPath) {
|
if !util.IsFileInputValid(certPath) {
|
||||||
logger.Warn(logSender, "", "unable to load invalid host certificate %#v", certPath)
|
logger.Warn(logSender, "", "unable to load invalid host certificate %#v", certPath)
|
||||||
logger.WarnToConsole("unable to load invalid host certificate %#v", certPath)
|
logger.WarnToConsole("unable to load invalid host certificate %#v", certPath)
|
||||||
|
@ -917,6 +921,7 @@ func (c *Configuration) loadHostCertificates(configDir string) ([]*ssh.Certifica
|
||||||
|
|
||||||
func (c *Configuration) initializeCertChecker(configDir string) error {
|
func (c *Configuration) initializeCertChecker(configDir string) error {
|
||||||
for _, keyPath := range c.TrustedUserCAKeys {
|
for _, keyPath := range c.TrustedUserCAKeys {
|
||||||
|
keyPath = strings.TrimSpace(keyPath)
|
||||||
if !util.IsFileInputValid(keyPath) {
|
if !util.IsFileInputValid(keyPath) {
|
||||||
logger.Warn(logSender, "", "unable to load invalid trusted user CA key %#v", keyPath)
|
logger.Warn(logSender, "", "unable to load invalid trusted user CA key %#v", keyPath)
|
||||||
logger.WarnToConsole("unable to load invalid trusted user CA key %#v", keyPath)
|
logger.WarnToConsole("unable to load invalid trusted user CA key %#v", keyPath)
|
||||||
|
|
|
@ -66,13 +66,16 @@ func IsStringPrefixInSlice(obj string, list []string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveDuplicates returns a new slice removing any duplicate element from the initial one
|
// RemoveDuplicates returns a new slice removing any duplicate element from the initial one
|
||||||
func RemoveDuplicates(obj []string) []string {
|
func RemoveDuplicates(obj []string, trim bool) []string {
|
||||||
if len(obj) == 0 {
|
if len(obj) == 0 {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
seen := make(map[string]bool)
|
seen := make(map[string]bool)
|
||||||
validIdx := 0
|
validIdx := 0
|
||||||
for _, item := range obj {
|
for _, item := range obj {
|
||||||
|
if trim {
|
||||||
|
item = strings.TrimSpace(item)
|
||||||
|
}
|
||||||
if !seen[item] {
|
if !seen[item] {
|
||||||
seen[item] = true
|
seen[item] = true
|
||||||
obj[validIdx] = item
|
obj[validIdx] = item
|
||||||
|
@ -462,7 +465,7 @@ func HTTPListenAndServe(srv *http.Server, address string, port int, isTLS bool,
|
||||||
func GetTLSCiphersFromNames(cipherNames []string) []uint16 {
|
func GetTLSCiphersFromNames(cipherNames []string) []uint16 {
|
||||||
var ciphers []uint16
|
var ciphers []uint16
|
||||||
|
|
||||||
for _, name := range RemoveDuplicates(cipherNames) {
|
for _, name := range RemoveDuplicates(cipherNames, false) {
|
||||||
for _, c := range tls.CipherSuites() {
|
for _, c := range tls.CipherSuites() {
|
||||||
if c.Name == strings.TrimSpace(name) {
|
if c.Name == strings.TrimSpace(name) {
|
||||||
ciphers = append(ciphers, c.ID)
|
ciphers = append(ciphers, c.ID)
|
||||||
|
|
|
@ -43,10 +43,10 @@ func (s *webDavServer) listenAndServe(compressor *middleware.Compressor) error {
|
||||||
}
|
}
|
||||||
if s.config.Cors.Enabled {
|
if s.config.Cors.Enabled {
|
||||||
c := cors.New(cors.Options{
|
c := cors.New(cors.Options{
|
||||||
AllowedOrigins: s.config.Cors.AllowedOrigins,
|
AllowedOrigins: util.RemoveDuplicates(s.config.Cors.AllowedOrigins, true),
|
||||||
AllowedMethods: s.config.Cors.AllowedMethods,
|
AllowedMethods: util.RemoveDuplicates(s.config.Cors.AllowedMethods, true),
|
||||||
AllowedHeaders: s.config.Cors.AllowedHeaders,
|
AllowedHeaders: util.RemoveDuplicates(s.config.Cors.AllowedHeaders, true),
|
||||||
ExposedHeaders: s.config.Cors.ExposedHeaders,
|
ExposedHeaders: util.RemoveDuplicates(s.config.Cors.ExposedHeaders, true),
|
||||||
MaxAge: s.config.Cors.MaxAge,
|
MaxAge: s.config.Cors.MaxAge,
|
||||||
AllowCredentials: s.config.Cors.AllowCredentials,
|
AllowCredentials: s.config.Cors.AllowCredentials,
|
||||||
OptionsPassthrough: true,
|
OptionsPassthrough: true,
|
||||||
|
|
Loading…
Reference in a new issue