package settings import ( "crypto/rand" "encoding/json" "fmt" "log" "strings" "time" "github.com/filebrowser/filebrowser/v2/rules" ) const DefaultUsersHomeBasePath = "/users" // AuthMethod describes an authentication method. type AuthMethod string // Settings contain the main settings of the application. type Settings struct { Key []byte `json:"key"` Signup bool `json:"signup"` CreateUserDir bool `json:"createUserDir"` UserHomeBasePath string `json:"userHomeBasePath"` Defaults UserDefaults `json:"defaults"` AuthMethod AuthMethod `json:"authMethod"` Branding Branding `json:"branding"` Tus Tus `json:"tus"` Commands map[string][]string `json:"commands"` Shell string `json:"shell"` Rules []rules.Rule `json:"rules"` } // GetRules implements rules.Provider. func (s *Settings) GetRules() []rules.Rule { return s.Rules } // Server specific settings. type Server struct { Root string `json:"root"` BaseURL string `json:"baseURL"` Socket string `json:"socket"` TLSKey string `json:"tlsKey"` TLSCert string `json:"tlsCert"` Port string `json:"port"` Address string `json:"address"` Log string `json:"log"` EnableThumbnails bool `json:"enableThumbnails"` ResizePreview bool `json:"resizePreview"` EnableExec bool `json:"enableExec"` TypeDetectionByHeader bool `json:"typeDetectionByHeader"` AuthHook string `json:"authHook"` TokenExpirationTime string `json:"tokenExpirationTime"` } // Clean cleans any variables that might need cleaning. func (s *Server) Clean() { s.BaseURL = strings.TrimSuffix(s.BaseURL, "/") } func (s *Server) GetTokenExpirationTime(fallback time.Duration) time.Duration { if s.TokenExpirationTime == "" { return fallback } duration, err := time.ParseDuration(s.TokenExpirationTime) if err != nil { log.Printf("[WARN] Failed to parse tokenExpirationTime: %v", err) return fallback } return duration } // GenerateKey generates a key of 512 bits. func GenerateKey() ([]byte, error) { b := make([]byte, 64) //nolint:gomnd _, err := rand.Read(b) // Note that err == nil only if we read len(b) bytes. if err != nil { return nil, err } return b, nil } // UnmarshalJSON implements custom JSON unmarshaling for Settings func (s *Settings) UnmarshalJSON(data []byte) error { type Alias Settings aux := &struct { Shell interface{} `json:"shell"` *Alias }{ Alias: (*Alias)(s), } if err := json.Unmarshal(data, &aux); err != nil { return err } // Handle the Shell field conversion switch v := aux.Shell.(type) { case string: s.Shell = v case []interface{}: // Convert array to string by joining elements var parts []string for _, item := range v { if str, ok := item.(string); ok { parts = append(parts, str) } } s.Shell = strings.Join(parts, " ") case nil: s.Shell = "" default: return fmt.Errorf("invalid type for shell field: %T", v) } return nil }