diff --git a/CHANGELOG.md b/CHANGELOG.md
index f40eb49e..5eb36e2d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,12 +5,16 @@ All notable changes to this project will be documented in this file. See [standa
# v0.2.0
- - Works with new more advanced filebrowser.json
- - improved GUI
+ - improved UI
- more unified coehisive look
+ - Adjusted header bar look and icon behavior
- The shell is dead.
- - If you need to use the shell, exec into the docker container.
- - All configuration is done via filebrowser.yml
+ - If you need to use custom commands, exec into the docker container.
+ - The json config file is dead.
+ - All configuration is done via advanced `filebrowser.yaml`
+ - The only flag that is allowed is flag to specify config file.
+ - Removed old code to migrate database versions
+ - Removed all unused cmd code
# v0.1.4
- various UI fixes
diff --git a/Dockerfile b/Dockerfile
index a0f628a7..4411460b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,7 +17,7 @@ RUN apk --no-cache add \
VOLUME /srv
EXPOSE 8080
WORKDIR /
-COPY --from=base /app/.filebrowser.json /.filebrowser.json
+COPY --from=base /app/settings/filebrowser.yaml /filebrowser.yaml
COPY --from=base /app/filebrowser /filebrowser
COPY --from=nbuild /app/dist/ /frontend/dist/
ENTRYPOINT [ "./filebrowser" ]
\ No newline at end of file
diff --git a/backend/auth/auth.go b/backend/auth/auth.go
index c3b143a8..a1121c6f 100644
--- a/backend/auth/auth.go
+++ b/backend/auth/auth.go
@@ -3,14 +3,13 @@ package auth
import (
"net/http"
- "github.com/gtsteffaniak/filebrowser/settings"
"github.com/gtsteffaniak/filebrowser/users"
)
// Auther is the authentication interface.
type Auther interface {
// Auth is called to authenticate a request.
- Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error)
+ Auth(r *http.Request, usr users.Store) (*users.User, error)
// LoginPage indicates if this auther needs a login page.
LoginPage() bool
}
diff --git a/backend/auth/hook.go b/backend/auth/hook.go
index 00b2a625..0ae5d143 100644
--- a/backend/auth/hook.go
+++ b/backend/auth/hook.go
@@ -31,7 +31,7 @@ type HookAuth struct {
}
// Auth authenticates the user via a json in content body.
-func (a *HookAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
+func (a *HookAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
var cred hookCred
if r.Body == nil {
@@ -44,8 +44,8 @@ func (a *HookAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings
}
a.Users = usr
- a.Settings = stg
- a.Server = srv
+ a.Settings = &settings.GlobalConfiguration
+ a.Server = &settings.GlobalConfiguration.Server
a.Cred = cred
action, err := a.RunCommand()
@@ -150,19 +150,18 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
if err != nil {
return nil, err
}
-
// create user with the provided credentials
d := &users.User{
Username: a.Cred.Username,
Password: pass,
- Scope: a.Settings.Defaults.Scope,
- Locale: a.Settings.Defaults.Locale,
- ViewMode: a.Settings.Defaults.ViewMode,
- SingleClick: a.Settings.Defaults.SingleClick,
- Sorting: a.Settings.Defaults.Sorting,
- Perm: a.Settings.Defaults.Perm,
- Commands: a.Settings.Defaults.Commands,
- HideDotfiles: a.Settings.Defaults.HideDotfiles,
+ Scope: a.Settings.UserDefaults.Scope,
+ Locale: a.Settings.UserDefaults.Locale,
+ ViewMode: a.Settings.UserDefaults.ViewMode,
+ SingleClick: a.Settings.UserDefaults.SingleClick,
+ Sorting: a.Settings.UserDefaults.Sorting,
+ Perm: a.Settings.UserDefaults.Perm,
+ Commands: a.Settings.UserDefaults.Commands,
+ HideDotfiles: a.Settings.UserDefaults.HideDotfiles,
}
u = a.GetUser(d)
@@ -219,7 +218,7 @@ func (a *HookAuth) GetUser(d *users.User) *users.User {
Password: d.Password,
Scope: a.Fields.GetString("user.scope", d.Scope),
Locale: a.Fields.GetString("user.locale", d.Locale),
- ViewMode: users.ViewMode(a.Fields.GetString("user.viewMode", string(d.ViewMode))),
+ ViewMode: d.ViewMode,
SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick),
Sorting: files.Sorting{
Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc),
diff --git a/backend/auth/json.go b/backend/auth/json.go
index ce7143de..d3734789 100644
--- a/backend/auth/json.go
+++ b/backend/auth/json.go
@@ -23,7 +23,8 @@ type JSONAuth struct {
}
// Auth authenticates the user via a json in content body.
-func (a JSONAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
+func (a JSONAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
+ config := &settings.GlobalConfiguration
var cred jsonCred
if r.Body == nil {
@@ -48,7 +49,7 @@ func (a JSONAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings,
}
}
- u, err := usr.Get(srv.Root, cred.Username)
+ u, err := usr.Get(config.Server.Root, cred.Username)
if err != nil || !users.CheckPwd(cred.Password, u.Password) {
return nil, os.ErrPermission
}
diff --git a/backend/auth/none.go b/backend/auth/none.go
index 6549780f..43688a26 100644
--- a/backend/auth/none.go
+++ b/backend/auth/none.go
@@ -14,8 +14,8 @@ const MethodNoAuth = "noauth"
type NoAuth struct{}
// Auth uses authenticates user 1.
-func (a NoAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
- return usr.Get(srv.Root, uint(1))
+func (a NoAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
+ return usr.Get(settings.GlobalConfiguration.Server.Root, uint(1))
}
// LoginPage tells that no auth doesn't require a login page.
diff --git a/backend/auth/proxy.go b/backend/auth/proxy.go
index a14e92a6..cf3e5936 100644
--- a/backend/auth/proxy.go
+++ b/backend/auth/proxy.go
@@ -4,8 +4,9 @@ import (
"net/http"
"os"
- "github.com/gtsteffaniak/filebrowser/errors"
"github.com/gtsteffaniak/filebrowser/settings"
+
+ "github.com/gtsteffaniak/filebrowser/errors"
"github.com/gtsteffaniak/filebrowser/users"
)
@@ -18,9 +19,9 @@ type ProxyAuth struct {
}
// Auth authenticates the user via an HTTP header.
-func (a ProxyAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
+func (a ProxyAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
username := r.Header.Get(a.Header)
- user, err := usr.Get(srv.Root, username)
+ user, err := usr.Get(settings.GlobalConfiguration.Server.Root, username)
if err == errors.ErrNotExist {
return nil, os.ErrPermission
}
diff --git a/backend/benchmark_results.txt b/backend/benchmark_results.txt
index 973bc2e5..655b1f9c 100644
--- a/backend/benchmark_results.txt
+++ b/backend/benchmark_results.txt
@@ -1,40 +1,42 @@
== Running benchmark ==
+/usr/local/go/bin/go
? github.com/gtsteffaniak/filebrowser [no test files]
? github.com/gtsteffaniak/filebrowser/auth [no test files]
? github.com/gtsteffaniak/filebrowser/cmd [no test files]
PASS
-ok github.com/gtsteffaniak/filebrowser/diskcache 0.588s
+ok github.com/gtsteffaniak/filebrowser/diskcache 0.004s
? github.com/gtsteffaniak/filebrowser/errors [no test files]
? github.com/gtsteffaniak/filebrowser/files [no test files]
PASS
-ok github.com/gtsteffaniak/filebrowser/fileutils 0.212s
-2023/08/18 17:10:41 h: 401
-2023/08/18 17:10:41 h: 401
-2023/08/18 17:10:41 h: 401
-2023/08/18 17:10:41 h: 401
-2023/08/18 17:10:41 h: 401
-2023/08/18 17:10:41 h: 401
+ok github.com/gtsteffaniak/filebrowser/fileutils 0.004s
+2023/09/02 19:15:20 h: 401
+2023/09/02 19:15:20 h: 401
+2023/09/02 19:15:20 h: 401
+2023/09/02 19:15:20 h: 401
+2023/09/02 19:15:20 h: 401
+2023/09/02 19:15:20 h: 401
PASS
-ok github.com/gtsteffaniak/filebrowser/http 0.753s
+ok github.com/gtsteffaniak/filebrowser/http 0.094s
PASS
-ok github.com/gtsteffaniak/filebrowser/img 0.362s
+ok github.com/gtsteffaniak/filebrowser/img 0.122s
PASS
-ok github.com/gtsteffaniak/filebrowser/rules 0.182s
+ok github.com/gtsteffaniak/filebrowser/rules 0.002s
PASS
-ok github.com/gtsteffaniak/filebrowser/runner 0.198s
-goos: darwin
-goarch: arm64
+ok github.com/gtsteffaniak/filebrowser/runner 0.004s
+goos: linux
+goarch: amd64
pkg: github.com/gtsteffaniak/filebrowser/search
-BenchmarkSearchAllIndexes-10 10 5802738 ns/op 2756774 B/op 42606 allocs/op
-BenchmarkFillIndex-10 10 4769329 ns/op 18512 B/op 453 allocs/op
+cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
+BenchmarkSearchAllIndexes-8 10 5176084 ns/op 2743632 B/op 42785 allocs/op
+BenchmarkFillIndex-8 10 3263308 ns/op 18485 B/op 453 allocs/op
PASS
-ok github.com/gtsteffaniak/filebrowser/search 0.356s
-? github.com/gtsteffaniak/filebrowser/settings [no test files]
+ok github.com/gtsteffaniak/filebrowser/search 0.109s
+PASS
+ok github.com/gtsteffaniak/filebrowser/settings 0.004s
? github.com/gtsteffaniak/filebrowser/share [no test files]
? github.com/gtsteffaniak/filebrowser/storage [no test files]
? github.com/gtsteffaniak/filebrowser/storage/bolt [no test files]
-? github.com/gtsteffaniak/filebrowser/storage/bolt/importer [no test files]
PASS
-ok github.com/gtsteffaniak/filebrowser/users 0.201s
+ok github.com/gtsteffaniak/filebrowser/users 0.004s
? github.com/gtsteffaniak/filebrowser/version [no test files]
diff --git a/backend/cmd/config.go b/backend/cmd/config.go
deleted file mode 100644
index 21d69d2a..00000000
--- a/backend/cmd/config.go
+++ /dev/null
@@ -1,163 +0,0 @@
-package cmd
-
-import (
- "encoding/json"
- nerrors "errors"
- "fmt"
- "os"
- "strings"
- "text/tabwriter"
-
- "github.com/spf13/cobra"
- "github.com/spf13/pflag"
-
- "github.com/gtsteffaniak/filebrowser/auth"
- "github.com/gtsteffaniak/filebrowser/errors"
- "github.com/gtsteffaniak/filebrowser/settings"
-)
-
-func init() {
- rootCmd.AddCommand(configCmd)
-}
-
-var configCmd = &cobra.Command{
- Use: "config",
- Short: "Configuration management utility",
- Long: `Configuration management utility.`,
- Args: cobra.NoArgs,
-}
-
-func addConfigFlags(flags *pflag.FlagSet) {
- addUserFlags(flags)
- flags.BoolP("signup", "s", false, "allow users to signup")
- flags.String("shell", "", "shell command to which other commands should be appended")
-
- flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
- flags.String("recaptcha.key", "", "ReCaptcha site key")
- flags.String("recaptcha.secret", "", "ReCaptcha secret")
-
- flags.String("frontend.name", "", "replace 'File Browser' by this name")
- flags.String("frontend.color", "", "set the theme color")
- flags.String("frontend.files", "", "path to directory with images and custom styles")
- flags.Bool("frontend.disableExternal", false, "disable external links such as GitHub links")
- flags.Bool("frontend.disableUsedPercentage", false, "disable used disk percentage graph")
-}
-
-//nolint:gocyclo
-func getAuthentication() (string, auth.Auther) {
- method := settings.GlobalConfiguration.Auth.Method
- var defaultAuther map[string]interface{}
- var auther auth.Auther
- if method == "proxy" {
- header := settings.GlobalConfiguration.Auth.Header
- if header == "" {
- header = defaultAuther["header"].(string)
- }
-
- if header == "" {
- checkErr(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
- }
-
- auther = &auth.ProxyAuth{Header: header}
- }
-
- if method == "noauth" {
- auther = &auth.NoAuth{}
- }
-
- if method == "password" {
- jsonAuth := &auth.JSONAuth{}
- host := settings.GlobalConfiguration.Auth.Recaptcha.Host
- key := settings.GlobalConfiguration.Auth.Recaptcha.Key
- secret := settings.GlobalConfiguration.Auth.Recaptcha.Secret
-
- if key == "" {
- if kmap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
- key = kmap["key"].(string)
- }
- }
-
- if secret == "" {
- if smap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
- secret = smap["secret"].(string)
- }
- }
-
- if key != "" && secret != "" {
- jsonAuth.ReCaptcha = &auth.ReCaptcha{
- Host: host,
- Key: key,
- Secret: secret,
- }
- }
- auther = jsonAuth
- }
-
- if method == "hook" {
- command := settings.GlobalConfiguration.Auth.Command
-
- if command == "" {
- command = defaultAuther["command"].(string)
- }
-
- if command == "" {
- checkErr(nerrors.New("you must set the flag 'auth.command' for method 'hook'"))
- }
-
- auther = &auth.HookAuth{Command: command}
- }
-
- if auther == nil {
- panic(errors.ErrInvalidAuthMethod)
- }
-
- return method, auther
-}
-
-func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) {
- w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) //nolint:gomnd
-
- fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
- fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
- fmt.Fprintf(w, "Auth method:\t%s\n", set.Auth.Method)
- fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
- fmt.Fprintln(w, "\nFrontend:")
- fmt.Fprintf(w, "\tName:\t%s\n", set.Frontend.Name)
- fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Frontend.Files)
- fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Frontend.DisableExternal)
- fmt.Fprintf(w, "\tDisable used disk percentage graph:\t%t\n", set.Frontend.DisableUsedPercentage)
- fmt.Fprintf(w, "\tColor:\t%s\n", set.Frontend.Color)
- fmt.Fprintln(w, "\nServer:")
- fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
- fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)
- fmt.Fprintf(w, "\tBase URL:\t%s\n", ser.BaseURL)
- fmt.Fprintf(w, "\tRoot:\t%s\n", ser.Root)
- fmt.Fprintf(w, "\tSocket:\t%s\n", ser.Socket)
- fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
- fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
- fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
- fmt.Fprintf(w, "\tExec Enabled:\t%t\n", ser.EnableExec)
- fmt.Fprintln(w, "\nDefaults:")
- fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
- fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
- fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
- fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
- fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
- fmt.Fprintf(w, "\tSorting:\n")
- fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
- fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)
- fmt.Fprintf(w, "\tPermissions:\n")
- fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin)
- fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute)
- fmt.Fprintf(w, "\t\tCreate:\t%t\n", set.Defaults.Perm.Create)
- fmt.Fprintf(w, "\t\tRename:\t%t\n", set.Defaults.Perm.Rename)
- fmt.Fprintf(w, "\t\tModify:\t%t\n", set.Defaults.Perm.Modify)
- fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete)
- fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share)
- fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download)
- w.Flush()
-
- b, err := json.MarshalIndent(auther, "", " ")
- checkErr(err)
- fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
-}
diff --git a/backend/cmd/config_cat.go b/backend/cmd/config_cat.go
deleted file mode 100644
index 3f06eb9f..00000000
--- a/backend/cmd/config_cat.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package cmd
-
-import (
- "github.com/spf13/cobra"
-)
-
-func init() {
- configCmd.AddCommand(configCatCmd)
-}
-
-var configCatCmd = &cobra.Command{
- Use: "cat",
- Short: "Prints the configuration",
- Long: `Prints the configuration.`,
- Args: cobra.NoArgs,
- Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
- set, err := d.store.Settings.Get()
- checkErr(err)
- ser, err := d.store.Settings.GetServer()
- checkErr(err)
- auther, err := d.store.Auth.Get(set.Auth.Method)
- checkErr(err)
- printSettings(ser, set, auther)
- }, pythonConfig{}),
-}
diff --git a/backend/cmd/config_export.go b/backend/cmd/config_export.go
deleted file mode 100644
index a4d8ecff..00000000
--- a/backend/cmd/config_export.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package cmd
-
-import (
- "github.com/spf13/cobra"
-)
-
-func init() {
- configCmd.AddCommand(configExportCmd)
-}
-
-var configExportCmd = &cobra.Command{
- Use: "export ",
- Short: "Export the configuration to a file",
- Long: `Export the configuration to a file. The path must be for a
-json or yaml file. This exported configuration can be changed,
-and imported again with 'config import' command.`,
- Args: jsonYamlArg,
- Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
- settings, err := d.store.Settings.Get()
- checkErr(err)
-
- server, err := d.store.Settings.GetServer()
- checkErr(err)
-
- auther, err := d.store.Auth.Get(settings.Auth.Method)
- checkErr(err)
-
- data := &settingsFile{
- Settings: settings,
- Auther: auther,
- Server: server,
- }
-
- err = marshal(args[0], data)
- checkErr(err)
- }, pythonConfig{}),
-}
diff --git a/backend/cmd/config_import.go b/backend/cmd/config_import.go
index 08ff806d..ed6702fc 100644
--- a/backend/cmd/config_import.go
+++ b/backend/cmd/config_import.go
@@ -3,9 +3,9 @@ package cmd
import (
"encoding/json"
"errors"
+ "log"
"path/filepath"
"reflect"
- "log"
"github.com/spf13/cobra"
@@ -13,10 +13,6 @@ import (
"github.com/gtsteffaniak/filebrowser/settings"
)
-func init() {
- configCmd.AddCommand(configImportCmd)
-}
-
type settingsFile struct {
Settings *settings.Settings `json:"settings"`
Server *settings.Server `json:"server"`
@@ -61,7 +57,7 @@ The path must be for a json or yaml file.`,
} else {
rawAuther = file.Auther
}
- log.Println("config_import",file.Settings.Auth)
+ log.Println("config_import", file.Settings.Auth)
var auther auth.Auther
switch file.Settings.Auth.Method {
case "password":
@@ -79,7 +75,6 @@ The path must be for a json or yaml file.`,
err = d.store.Auth.Save(auther)
checkErr(err)
- printSettings(file.Server, file.Settings, auther)
}, pythonConfig{allowNoDB: true}),
}
diff --git a/backend/cmd/config_init.go b/backend/cmd/config_init.go
index 47bf8df7..758f3da5 100644
--- a/backend/cmd/config_init.go
+++ b/backend/cmd/config_init.go
@@ -5,14 +5,11 @@ import (
"github.com/spf13/cobra"
+ "github.com/gtsteffaniak/filebrowser/auth"
+ "github.com/gtsteffaniak/filebrowser/errors"
"github.com/gtsteffaniak/filebrowser/settings"
)
-func init() {
- configCmd.AddCommand(configInitCmd)
- addConfigFlags(configInitCmd.Flags())
-}
-
var configInitCmd = &cobra.Command{
Use: "init",
Short: "Initialize a new database",
@@ -23,14 +20,12 @@ to the defaults when creating new users and you don't
override the options.`,
Args: cobra.NoArgs,
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
- defaults := settings.UserDefaults{}
- flags := cmd.Flags()
- getUserDefaults(flags, &defaults, true)
- _, auther := getAuthentication()
- ser := &settings.GlobalConfiguration.Server
- err := d.store.Settings.Save(&settings.GlobalConfiguration)
+ auther := getAuthentication()
+ s := settings.GlobalConfiguration
+ s.Key = generateKey()
+ err := d.store.Settings.Save(&s)
checkErr(err)
- err = d.store.Settings.SaveServer(ser)
+ err = d.store.Settings.SaveServer(&s.Server)
checkErr(err)
err = d.store.Auth.Save(auther)
checkErr(err)
@@ -40,6 +35,45 @@ Congratulations! You've set up your database to use with File Browser.
Now add your first user via 'filebrowser users add' and then you just
need to call the main command to boot up the server.
`)
- printSettings(ser, &settings.GlobalConfiguration, auther)
}, pythonConfig{noDB: true}),
}
+
+//nolint:gocyclo
+func getAuthentication() auth.Auther {
+ method := settings.GlobalConfiguration.Auth.Method
+ var auther auth.Auther
+ if method == "proxy" {
+ header := settings.GlobalConfiguration.Auth.Header
+ auther = &auth.ProxyAuth{Header: header}
+ }
+
+ if method == "noauth" {
+ auther = &auth.NoAuth{}
+ }
+
+ if method == "password" {
+ jsonAuth := &auth.JSONAuth{}
+ host := settings.GlobalConfiguration.Auth.Recaptcha.Host
+ key := settings.GlobalConfiguration.Auth.Recaptcha.Key
+ secret := settings.GlobalConfiguration.Auth.Recaptcha.Secret
+ if key != "" && secret != "" {
+ jsonAuth.ReCaptcha = &auth.ReCaptcha{
+ Host: host,
+ Key: key,
+ Secret: secret,
+ }
+ }
+ auther = jsonAuth
+ }
+
+ if method == "hook" {
+ command := settings.GlobalConfiguration.Auth.Command
+ auther = &auth.HookAuth{Command: command}
+ }
+
+ if auther == nil {
+ panic(errors.ErrInvalidAuthMethod)
+ }
+
+ return auther
+}
diff --git a/backend/cmd/config_set.go b/backend/cmd/config_set.go
deleted file mode 100644
index d7bb80d9..00000000
--- a/backend/cmd/config_set.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package cmd
-
-import (
- "github.com/spf13/cobra"
- "github.com/spf13/pflag"
-)
-
-func init() {
- configCmd.AddCommand(configSetCmd)
- addConfigFlags(configSetCmd.Flags())
-}
-
-var configSetCmd = &cobra.Command{
- Use: "set",
- Short: "Updates the configuration",
- Long: `Updates the configuration. Set the flags for the options
-you want to change. Other options will remain unchanged.`,
- Args: cobra.NoArgs,
- Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
- flags := cmd.Flags()
- set, err := d.store.Settings.Get()
- checkErr(err)
-
- ser, err := d.store.Settings.GetServer()
- checkErr(err)
-
- flags.Visit(func(flag *pflag.Flag) {
- switch flag.Name {
- case "baseurl":
- ser.BaseURL = mustGetString(flags, flag.Name)
- case "root":
- ser.Root = mustGetString(flags, flag.Name)
- case "socket":
- ser.Socket = mustGetString(flags, flag.Name)
- case "cert":
- ser.TLSCert = mustGetString(flags, flag.Name)
- case "key":
- ser.TLSKey = mustGetString(flags, flag.Name)
- case "address":
- ser.Address = mustGetString(flags, flag.Name)
- case "port":
- ser.Port = 8080
- case "log":
- ser.Log = mustGetString(flags, flag.Name)
- case "signup":
- set.Signup = mustGetBool(flags, flag.Name)
- case "shell":
- set.Shell = convertCmdStrToCmdArray(mustGetString(flags, flag.Name))
- case "frontend.name":
- set.Frontend.Name = mustGetString(flags, flag.Name)
- case "frontend.color":
- set.Frontend.Color = mustGetString(flags, flag.Name)
- case "frontend.disableExternal":
- set.Frontend.DisableExternal = mustGetBool(flags, flag.Name)
- case "frontend.disableUsedPercentage":
- set.Frontend.DisableUsedPercentage = mustGetBool(flags, flag.Name)
- case "frontend.files":
- set.Frontend.Files = mustGetString(flags, flag.Name)
- }
- })
-
- getUserDefaults(flags, &set.Defaults, false)
-
- // read the defaults
- _, auther := getAuthentication()
- err = d.store.Auth.Save(auther)
- checkErr(err)
- err = d.store.Settings.Save(set)
- checkErr(err)
- err = d.store.Settings.SaveServer(ser)
- checkErr(err)
- printSettings(ser, set, auther)
- }, pythonConfig{}),
-}
diff --git a/backend/cmd/root.go b/backend/cmd/root.go
index 774211ed..2e823472 100644
--- a/backend/cmd/root.go
+++ b/backend/cmd/root.go
@@ -142,6 +142,12 @@ user created with the credentials from options "username" and "password".`,
}, pythonConfig{allowNoDB: true}),
}
+func StartFilebrowser() {
+ if err := rootCmd.Execute(); err != nil {
+ log.Fatal(err)
+ }
+}
+
func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfacer
sig := <-c
log.Printf("Caught signal %s: shutting down.", sig)
@@ -204,50 +210,18 @@ func setupLog(logMethod string) {
}
func quickSetup(flags *pflag.FlagSet, d pythonData) {
- set := &settings.Settings{
- Key: generateKey(),
- Signup: false,
- CreateUserDir: false,
- UserHomeBasePath: settings.DefaultUsersHomeBasePath,
- Defaults: settings.UserDefaults{
- Scope: ".",
- Locale: "en",
- SingleClick: false,
- Perm: users.Permissions{
- Admin: false,
- Execute: true,
- Create: true,
- Rename: true,
- Modify: true,
- Delete: true,
- Share: true,
- Download: true,
- },
- },
- Frontend: settings.Frontend{},
- Commands: nil,
- Shell: nil,
- Rules: nil,
- }
+ settings.GlobalConfiguration.Key = generateKey()
var err error
if settings.GlobalConfiguration.Auth.Method == "noauth" {
- set.Auth.Method = "noauth"
+ settings.GlobalConfiguration.Auth.Method = "noauth"
err = d.store.Auth.Save(&auth.NoAuth{})
} else {
- set.Auth.Method = "password"
+ settings.GlobalConfiguration.Auth.Method = "password"
err = d.store.Auth.Save(&auth.JSONAuth{})
}
- err = d.store.Settings.Save(set)
+ err = d.store.Settings.Save(&settings.GlobalConfiguration)
checkErr(err)
-
- ser := &settings.Server{
- BaseURL: getParam(flags, "baseurl"),
- Log: getParam(flags, "log"),
- TLSKey: getParam(flags, "key"),
- TLSCert: getParam(flags, "cert"),
- Root: getParam(flags, "root"),
- }
- err = d.store.Settings.SaveServer(ser)
+ err = d.store.Settings.SaveServer(&settings.GlobalConfiguration.Server)
checkErr(err)
username := getParam(flags, "username")
@@ -268,7 +242,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
LockPassword: false,
}
- set.Defaults.Apply(user)
+ settings.GlobalConfiguration.UserDefaults.Apply(user)
user.Perm.Admin = true
err = d.store.Users.Save(user)
diff --git a/backend/cmd/upgrade.go b/backend/cmd/upgrade.go
deleted file mode 100644
index be9769c2..00000000
--- a/backend/cmd/upgrade.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package cmd
-
-import (
- "github.com/spf13/cobra"
-
- "github.com/gtsteffaniak/filebrowser/storage/bolt/importer"
-)
-
-func init() {
- rootCmd.AddCommand(upgradeCmd)
-
- upgradeCmd.Flags().String("old.database", "", "")
- upgradeCmd.Flags().String("old.config", "", "")
- _ = upgradeCmd.MarkFlagRequired("old.database")
-}
-
-var upgradeCmd = &cobra.Command{
- Use: "upgrade",
- Short: "Upgrades an old configuration",
- Long: `Upgrades an old configuration. This command DOES NOT
-import share links because they are incompatible with
-this version.`,
- Args: cobra.NoArgs,
- Run: func(cmd *cobra.Command, args []string) {
- flags := cmd.Flags()
- oldDB := mustGetString(flags, "old.database")
- oldConf := mustGetString(flags, "old.config")
- err := importer.Import(oldDB, oldConf, getParam(flags, "database"))
- checkErr(err)
- },
-}
diff --git a/backend/cmd/users.go b/backend/cmd/users.go
index 3c835a18..1f50cf74 100644
--- a/backend/cmd/users.go
+++ b/backend/cmd/users.go
@@ -79,8 +79,8 @@ func addUserFlags(flags *pflag.FlagSet) {
flags.Bool("singleClick", false, "use single clicks only")
}
-func getViewMode(flags *pflag.FlagSet) users.ViewMode {
- viewMode := users.ViewMode(mustGetString(flags, "viewMode"))
+func getViewMode(flags *pflag.FlagSet) string {
+ viewMode := settings.GlobalConfiguration.UserDefaults.ViewMode
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode {
checkErr(errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(users.MosaicViewMode) + "\""))
}
diff --git a/backend/cmd/users_add.go b/backend/cmd/users_add.go
index f133a464..0ba430eb 100644
--- a/backend/cmd/users_add.go
+++ b/backend/cmd/users_add.go
@@ -19,7 +19,6 @@ var usersAddCmd = &cobra.Command{
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
s, err := d.store.Settings.Get()
checkErr(err)
- getUserDefaults(cmd.Flags(), &s.Defaults, false)
password, err := users.HashPwd(args[1])
checkErr(err)
@@ -30,7 +29,7 @@ var usersAddCmd = &cobra.Command{
LockPassword: mustGetBool(cmd.Flags(), "lockPassword"),
}
- s.Defaults.Apply(user)
+ s.UserDefaults.Apply(user)
servSettings, err := d.store.Settings.GetServer()
checkErr(err)
diff --git a/backend/cmd/users_update.go b/backend/cmd/users_update.go
index 09bb4b8d..04dd7ce5 100644
--- a/backend/cmd/users_update.go
+++ b/backend/cmd/users_update.go
@@ -49,7 +49,6 @@ options you want to change.`,
Sorting: user.Sorting,
Commands: user.Commands,
}
- getUserDefaults(flags, &defaults, false)
user.Scope = defaults.Scope
user.Locale = defaults.Locale
user.ViewMode = defaults.ViewMode
diff --git a/backend/cmd/utils.go b/backend/cmd/utils.go
index ef0b9a7c..0ae50265 100644
--- a/backend/cmd/utils.go
+++ b/backend/cmd/utils.go
@@ -85,8 +85,7 @@ func dbExists(path string) (bool, error) {
func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
return func(cmd *cobra.Command, args []string) {
data := pythonData{hadDB: true}
-
- path := getParam(cmd.Flags(), "database")
+ path := settings.GlobalConfiguration.Server.Database
exists, err := dbExists(path)
if err != nil {
@@ -100,6 +99,7 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
data.hadDB = exists
db, err := storm.Open(path)
checkErr(err)
+
defer db.Close()
data.store, err = bolt.NewStorage(db)
checkErr(err)
diff --git a/backend/filebrowser.yml b/backend/filebrowser.yaml
similarity index 67%
rename from backend/filebrowser.yml
rename to backend/filebrowser.yaml
index f68917f4..6a202701 100644
--- a/backend/filebrowser.yml
+++ b/backend/filebrowser.yaml
@@ -1,6 +1,6 @@
server:
- indexingInterval: 5
- numImageProcessors: 2
+ indexingInterval: 60
+ numImageProcessors: 8
socket: ""
tlsKey: ""
tlsCert: ""
@@ -21,12 +21,12 @@ auth:
header: ""
method: noauth
command: ""
- signup: false
+ signup: true
shell: ""
frontend:
name: ""
disableExternal: false
- disableUsedPercentage: false
+ disableUsedPercentage: true
files: ""
theme: ""
color: ""
@@ -37,16 +37,16 @@ userDefaults:
singleClick: false
sorting:
by: ""
- asc: false
+ asc: true
perm:
- admin: false
- execute: false
- create: false
- rename: false
- modify: false
- delete: false
- share: false
- download: false
+ admin: true
+ execute: true
+ create: true
+ rename: true
+ modify: true
+ delete: true
+ share: true
+ download: true
commands: []
- hideDotfiles: false
+ hideDotfiles: true
dateFormat: false
diff --git a/backend/go.mod b/backend/go.mod
index f2ab4898..63bde874 100644
--- a/backend/go.mod
+++ b/backend/go.mod
@@ -9,12 +9,11 @@ require (
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
github.com/goccy/go-yaml v1.11.0
github.com/golang-jwt/jwt/v4 v4.5.0
+ github.com/google/go-cmp v0.5.9
github.com/gorilla/mux v1.8.0
- github.com/gorilla/websocket v1.5.0
github.com/maruel/natural v1.1.0
github.com/marusama/semaphore/v2 v2.5.0
github.com/mholt/archiver/v3 v3.5.1
- github.com/pelletier/go-toml/v2 v2.0.9
github.com/shirou/gopsutil/v3 v3.23.7
github.com/spf13/afero v1.9.5
github.com/spf13/cobra v1.7.0
@@ -22,7 +21,6 @@ require (
github.com/spf13/viper v1.16.0
github.com/stretchr/testify v1.8.4
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
- go.etcd.io/bbolt v1.3.7
golang.org/x/crypto v0.12.0
golang.org/x/image v0.11.0
golang.org/x/text v0.12.0
@@ -51,6 +49,7 @@ require (
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
+ github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/pierrec/lz4/v4 v4.1.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
@@ -60,6 +59,7 @@ require (
github.com/ulikunitz/xz v0.5.9 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
+ go.etcd.io/bbolt v1.3.7 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
diff --git a/backend/go.sum b/backend/go.sum
index ebb50138..5aa94277 100644
--- a/backend/go.sum
+++ b/backend/go.sum
@@ -178,8 +178,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
diff --git a/backend/http/auth.go b/backend/http/auth.go
index a47baec5..53dda241 100644
--- a/backend/http/auth.go
+++ b/backend/http/auth.go
@@ -22,7 +22,7 @@ const (
type userInfo struct {
ID uint `json:"id"`
Locale string `json:"locale"`
- ViewMode users.ViewMode `json:"viewMode"`
+ ViewMode string `json:"viewMode"`
SingleClick bool `json:"singleClick"`
Perm users.Permissions `json:"perm"`
Commands []string `json:"commands"`
@@ -107,7 +107,7 @@ var loginHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int, e
return http.StatusInternalServerError, err
}
- user, err := auther.Auth(r, d.store.Users, d.settings, d.server)
+ user, err := auther.Auth(r, d.store.Users)
if err == os.ErrPermission {
return http.StatusForbidden, nil
} else if err != nil {
@@ -145,7 +145,7 @@ var signupHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int,
Username: info.Username,
}
- d.settings.Defaults.Apply(user)
+ d.settings.UserDefaults.Apply(user)
pwd, err := users.HashPwd(info.Password)
if err != nil {
@@ -177,6 +177,7 @@ var renewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data
})
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User) (int, error) {
+ log.Printf("%#v", user)
claims := &authToken{
User: userInfo{
ID: user.ID,
diff --git a/backend/http/commands.go b/backend/http/commands.go
deleted file mode 100644
index cf886541..00000000
--- a/backend/http/commands.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package http
-
-import (
- "bufio"
- "io"
- "log"
- "net/http"
- "os/exec"
- "strings"
- "time"
-
- "github.com/gorilla/websocket"
-
- "github.com/gtsteffaniak/filebrowser/runner"
-)
-
-const (
- WSWriteDeadline = 10 * time.Second
-)
-
-var upgrader = websocket.Upgrader{
- ReadBufferSize: 1024,
- WriteBufferSize: 1024,
-}
-
-var (
- cmdNotAllowed = []byte("Command not allowed.")
-)
-
-//nolint:unparam
-func wsErr(ws *websocket.Conn, r *http.Request, status int, err error) {
- txt := http.StatusText(status)
- if err != nil || status >= 400 {
- log.Printf("%s: %v %s %v", r.URL.Path, status, r.RemoteAddr, err)
- }
- if err := ws.WriteControl(websocket.CloseInternalServerErr, []byte(txt), time.Now().Add(WSWriteDeadline)); err != nil {
- log.Print(err)
- }
-}
-
-var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
- conn, err := upgrader.Upgrade(w, r, nil)
- if err != nil {
- return http.StatusInternalServerError, err
- }
- defer conn.Close()
-
- var raw string
-
- for {
- _, msg, err := conn.ReadMessage() //nolint:govet
- if err != nil {
- wsErr(conn, r, http.StatusInternalServerError, err)
- return 0, nil
- }
-
- raw = strings.TrimSpace(string(msg))
- if raw != "" {
- break
- }
- }
-
- command, err := runner.ParseCommand(d.settings, raw)
- if err != nil {
- if err := conn.WriteMessage(websocket.TextMessage, []byte(err.Error())); err != nil { //nolint:govet
- wsErr(conn, r, http.StatusInternalServerError, err)
- }
- return 0, nil
- }
-
- if !d.server.EnableExec || !d.user.CanExecute(command[0]) {
- if err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed); err != nil { //nolint:govet
- wsErr(conn, r, http.StatusInternalServerError, err)
- }
-
- return 0, nil
- }
-
- cmd := exec.Command(command[0], command[1:]...) //nolint:gosec
- cmd.Dir = d.user.FullPath(r.URL.Path)
-
- stdout, err := cmd.StdoutPipe()
- if err != nil {
- wsErr(conn, r, http.StatusInternalServerError, err)
- return 0, nil
- }
-
- stderr, err := cmd.StderrPipe()
- if err != nil {
- wsErr(conn, r, http.StatusInternalServerError, err)
- return 0, nil
- }
-
- if err := cmd.Start(); err != nil {
- wsErr(conn, r, http.StatusInternalServerError, err)
- return 0, nil
- }
-
- s := bufio.NewScanner(io.MultiReader(stdout, stderr))
- for s.Scan() {
- if err := conn.WriteMessage(websocket.TextMessage, s.Bytes()); err != nil {
- log.Print(err)
- }
- }
-
- if err := cmd.Wait(); err != nil {
- wsErr(conn, r, http.StatusInternalServerError, err)
- }
-
- return 0, nil
-})
diff --git a/backend/http/http.go b/backend/http/http.go
index 2ef52c10..f12470fd 100644
--- a/backend/http/http.go
+++ b/backend/http/http.go
@@ -32,58 +32,44 @@ func NewHandler(
})
})
index, static := getStaticHandlers(store, server, assetsFs)
-
// NOTE: This fixes the issue where it would redirect if people did not put a
// trailing slash in the end. I hate this decision since this allows some awful
// URLs https://www.gorillatoolkit.org/pkg/mux#Router.SkipClean
r = r.SkipClean(true)
-
monkey := func(fn handleFunc, prefix string) http.Handler {
return handle(fn, prefix, store, server)
}
-
r.HandleFunc("/health", healthHandler)
r.PathPrefix("/static").Handler(static)
r.NotFoundHandler = index
-
api := r.PathPrefix("/api").Subrouter()
-
api.Handle("/login", monkey(loginHandler, ""))
api.Handle("/signup", monkey(signupHandler, ""))
api.Handle("/renew", monkey(renewHandler, ""))
-
users := api.PathPrefix("/users").Subrouter()
users.Handle("", monkey(usersGetHandler, "")).Methods("GET")
users.Handle("", monkey(userPostHandler, "")).Methods("POST")
users.Handle("/{id:[0-9]+}", monkey(userPutHandler, "")).Methods("PUT")
users.Handle("/{id:[0-9]+}", monkey(userGetHandler, "")).Methods("GET")
users.Handle("/{id:[0-9]+}", monkey(userDeleteHandler, "")).Methods("DELETE")
-
api.PathPrefix("/resources").Handler(monkey(resourceGetHandler, "/api/resources")).Methods("GET")
api.PathPrefix("/resources").Handler(monkey(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE")
api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST")
api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT")
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH")
-
api.PathPrefix("/usage").Handler(monkey(diskUsage, "/api/usage")).Methods("GET")
-
api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).Methods("GET")
api.PathPrefix("/share").Handler(monkey(shareGetsHandler, "/api/share")).Methods("GET")
api.PathPrefix("/share").Handler(monkey(sharePostHandler, "/api/share")).Methods("POST")
api.PathPrefix("/share").Handler(monkey(shareDeleteHandler, "/api/share")).Methods("DELETE")
-
api.Handle("/settings", monkey(settingsGetHandler, "")).Methods("GET")
api.Handle("/settings", monkey(settingsPutHandler, "")).Methods("PUT")
-
api.PathPrefix("/raw").Handler(monkey(rawHandler, "/api/raw")).Methods("GET")
api.PathPrefix("/preview/{size}/{path:.*}").
Handler(monkey(previewHandler(imgSvc, fileCache, server.EnableThumbnails, server.ResizePreview), "/api/preview")).Methods("GET")
- api.PathPrefix("/command").Handler(monkey(commandsHandler, "/api/command")).Methods("GET")
api.PathPrefix("/search").Handler(monkey(searchHandler, "/api/search")).Methods("GET")
-
public := api.PathPrefix("/public").Subrouter()
public.PathPrefix("/dl").Handler(monkey(publicDlHandler, "/api/public/dl/")).Methods("GET")
public.PathPrefix("/share").Handler(monkey(publicShareHandler, "/api/public/share/")).Methods("GET")
-
return stripPrefix(server.BaseURL, r), nil
}
diff --git a/backend/http/settings.go b/backend/http/settings.go
index 49c77326..9591df5d 100644
--- a/backend/http/settings.go
+++ b/backend/http/settings.go
@@ -24,7 +24,7 @@ var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
Signup: d.settings.Signup,
CreateUserDir: d.settings.CreateUserDir,
UserHomeBasePath: d.settings.UserHomeBasePath,
- Defaults: d.settings.Defaults,
+ Defaults: d.settings.UserDefaults,
Rules: d.settings.Rules,
Frontend: d.settings.Frontend,
Shell: d.settings.Shell,
@@ -44,7 +44,7 @@ var settingsPutHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
d.settings.Signup = req.Signup
d.settings.CreateUserDir = req.CreateUserDir
d.settings.UserHomeBasePath = req.UserHomeBasePath
- d.settings.Defaults = req.Defaults
+ d.settings.UserDefaults = req.Defaults
d.settings.Rules = req.Rules
d.settings.Frontend = req.Frontend
d.settings.Shell = req.Shell
diff --git a/backend/main.go b/backend/main.go
index 0859625e..3b127cff 100644
--- a/backend/main.go
+++ b/backend/main.go
@@ -2,8 +2,10 @@ package main
import (
"github.com/gtsteffaniak/filebrowser/cmd"
+ "github.com/gtsteffaniak/filebrowser/settings"
)
func main() {
- cmd.Execute()
+ settings.Initialize()
+ cmd.StartFilebrowser()
}
diff --git a/backend/run_benchmark.sh b/backend/run_benchmark.sh
index 5e8e34cd..b9e2a2f0 100755
--- a/backend/run_benchmark.sh
+++ b/backend/run_benchmark.sh
@@ -1,6 +1,5 @@
#!/bin/sh
## TEST file used by docker testing containers
-touch render.yml
checkExit() {
if [ "$?" -ne 0 ];then
exit 1
diff --git a/backend/run_tests.sh b/backend/run_tests.sh
index f20b80b0..fc278bb2 100755
--- a/backend/run_tests.sh
+++ b/backend/run_tests.sh
@@ -1,6 +1,5 @@
#!/bin/sh
## TEST file used by docker testing containers
-touch render.yml
checkExit() {
if [ "$?" -ne 0 ];then
exit 1
diff --git a/backend/settings/config.go b/backend/settings/config.go
index c0c427dd..751b0406 100644
--- a/backend/settings/config.go
+++ b/backend/settings/config.go
@@ -8,18 +8,30 @@ import (
)
var GlobalConfiguration Settings
+var configYml = "filebrowser.yaml"
-func init() {
- // Open and read the YAML file
- yamlFile, err := os.Open("filebrowser.yml")
+func Initialize() {
+ yamlData := loadConfigFile()
+ GlobalConfiguration = setDefaults()
+ err := yaml.Unmarshal(yamlData, &GlobalConfiguration)
if err != nil {
- log.Fatalf("Error opening YAML file: %v", err)
+ log.Fatalf("Error unmarshaling YAML data: %v", err)
+ }
+}
+
+func loadConfigFile() []byte {
+ // Open and read the YAML file
+ yamlFile, err := os.Open(configYml)
+ if err != nil {
+ log.Printf("Error opening config file: %v\nUsing default config only", err)
+ setDefaults()
+ return []byte{}
}
defer yamlFile.Close()
stat, err := yamlFile.Stat()
if err != nil {
- log.Fatalf("Error getting file information: %v", err)
+ log.Fatalf("Error getting file information: %s", err.Error())
}
yamlData := make([]byte, stat.Size())
@@ -27,23 +39,16 @@ func init() {
if err != nil {
log.Fatalf("Error reading YAML data: %v", err)
}
- setDefaults()
- // Unmarshal the YAML data into the Settings struct
- err = yaml.Unmarshal(yamlData, &GlobalConfiguration)
- if err != nil {
- log.Fatalf("Error unmarshaling YAML data: %v", err)
- }
- // Now you have the Settings struct with values from the YAML file
- // You can access the values like: defaultSettings.Key, defaultSettings.Server.Port, etc.
+ return yamlData
}
-func setDefaults() {
- GlobalConfiguration = Settings{
+func setDefaults() Settings {
+ return Settings{
Signup: true,
Server: Server{
IndexingInterval: 5,
Port: 8080,
- NumImageProcessors: 1,
+ NumImageProcessors: 4,
BaseURL: "",
},
Auth: Auth{
@@ -52,5 +57,8 @@ func setDefaults() {
Host: "",
},
},
+ UserDefaults: UserDefaults{
+ HideDotfiles: true,
+ },
}
}
diff --git a/backend/settings/settings_test.go b/backend/settings/settings_test.go
new file mode 100644
index 00000000..7eefacd7
--- /dev/null
+++ b/backend/settings/settings_test.go
@@ -0,0 +1,46 @@
+package settings
+
+import (
+ "log"
+ "testing"
+
+ "github.com/goccy/go-yaml"
+ "github.com/google/go-cmp/cmp"
+)
+
+func TestConfigLoadChanged(t *testing.T) {
+ configYml = "./testingConfig.yaml"
+ yamlData := loadConfigFile()
+ // Marshal the YAML data to a more human-readable format
+ newConfig := setDefaults()
+ GlobalConfiguration := setDefaults()
+
+ err := yaml.Unmarshal(yamlData, &newConfig)
+ if err != nil {
+ log.Fatalf("Error unmarshaling YAML data: %v", err)
+ }
+ // Use go-cmp to compare the two structs
+ if diff := cmp.Diff(newConfig, GlobalConfiguration); diff == "" {
+ t.Errorf("No change when there should have been (-want +got):\n%s", diff)
+ }
+}
+
+func TestConfigLoadSpecificValues(t *testing.T) {
+ configYml = "./testingConfig.yaml"
+ yamlData := loadConfigFile()
+ // Marshal the YAML data to a more human-readable format
+ newConfig := setDefaults()
+ GlobalConfiguration := setDefaults()
+
+ err := yaml.Unmarshal(yamlData, &newConfig)
+ if err != nil {
+ log.Fatalf("Error unmarshaling YAML data: %v", err)
+ }
+
+ if GlobalConfiguration.Auth.Method == newConfig.Auth.Method {
+ log.Fatalf("Differences should have been found, but were not on Auth method")
+ }
+ if GlobalConfiguration.UserDefaults.HideDotfiles == newConfig.UserDefaults.HideDotfiles {
+ log.Fatalf("Differences should have been found, but were not on Auth method")
+ }
+}
diff --git a/backend/settings/storage.go b/backend/settings/storage.go
index a027b4b3..19c8fdcc 100644
--- a/backend/settings/storage.go
+++ b/backend/settings/storage.go
@@ -50,16 +50,16 @@ func (s *Storage) Save(set *Settings) error {
return errors.ErrEmptyKey
}
- if set.Defaults.Locale == "" {
- set.Defaults.Locale = "en"
+ if set.UserDefaults.Locale == "" {
+ set.UserDefaults.Locale = "en"
}
- if set.Defaults.Commands == nil {
- set.Defaults.Commands = []string{}
+ if set.UserDefaults.Commands == nil {
+ set.UserDefaults.Commands = []string{}
}
- if set.Defaults.ViewMode == "" {
- set.Defaults.ViewMode = users.MosaicViewMode
+ if set.UserDefaults.ViewMode == "" {
+ set.UserDefaults.ViewMode = users.MosaicViewMode
}
if set.Rules == nil {
diff --git a/backend/settings/structs.go b/backend/settings/structs.go
index fba392e7..84401379 100644
--- a/backend/settings/structs.go
+++ b/backend/settings/structs.go
@@ -1,7 +1,6 @@
package settings
import (
- "github.com/gtsteffaniak/filebrowser/files"
"github.com/gtsteffaniak/filebrowser/rules"
"github.com/gtsteffaniak/filebrowser/users"
)
@@ -24,31 +23,28 @@ type Settings struct {
Signup bool `json:"signup"`
CreateUserDir bool `json:"createUserDir"`
UserHomeBasePath string `json:"userHomeBasePath"`
- Defaults UserDefaults `json:"defaults"`
Commands map[string][]string `json:"commands"`
Shell []string `json:"shell"`
Rules []rules.Rule `json:"rules"`
Server Server `json:"server"`
Auth Auth `json:"auth"`
-
- Frontend Frontend `json:"frontend"`
-
- UserDefaults UserDefaults `json:"userDefaults"`
+ Frontend Frontend `json:"frontend"`
+ UserDefaults UserDefaults `json:"userDefaults"`
}
type Auth struct {
- Recaptcha Recaptcha
- Header string `json:"header"`
- Method string `json:"method"`
- Command string `json:"command"`
- Signup bool `json:"signup"`
- Shell string `json:"shell"`
+ Recaptcha Recaptcha `json:"recaptcha"`
+ Header string `json:"header"`
+ Method string `json:"method"`
+ Command string `json:"command"`
+ Signup bool `json:"signup"`
+ Shell string `json:"shell"`
}
type Recaptcha struct {
- Host string
- Key string
- Secret string
+ Host string `json:"host"`
+ Key string `json:"key"`
+ Secret string `json:"secret"`
}
type Server struct {
@@ -68,7 +64,6 @@ type Server struct {
Log string `json:"log"`
Database string `json:"database"`
Root string `json:"root"`
- EnablePreviewResize bool `json:"disable-preview-resize"`
}
type Frontend struct {
@@ -83,55 +78,25 @@ type Frontend struct {
// UserDefaults is a type that holds the default values
// for some fields on User.
type UserDefaults struct {
- Scope string `json:"scope"`
- Locale string `json:"locale"`
- ViewMode users.ViewMode `json:"viewMode"`
- SingleClick bool `json:"singleClick"`
- Sorting files.Sorting `json:"sorting"`
- Perm users.Permissions `json:"perm"`
- Commands []string `json:"commands"`
- HideDotfiles bool `json:"hideDotfiles"`
- DateFormat bool `json:"dateFormat"`
+ Scope string `json:"scope"`
+ Locale string `json:"locale"`
+ ViewMode string `json:"viewMode"`
+ SingleClick bool `json:"singleClick"`
+ Sorting struct {
+ By string `json:"by"`
+ Asc bool `json:"asc"`
+ } `json:"sorting"`
+ Perm struct {
+ Admin bool `json:"admin"`
+ Execute bool `json:"execute"`
+ Create bool `json:"create"`
+ Rename bool `json:"rename"`
+ Modify bool `json:"modify"`
+ Delete bool `json:"delete"`
+ Share bool `json:"share"`
+ Download bool `json:"download"`
+ } `json:"perm"`
+ Commands []string `json:"commands"`
+ HideDotfiles bool `json:"hideDotfiles"`
+ DateFormat bool `json:"dateFormat"`
}
-
-//{
-// "server":{
-// "port":8080,
-// "baseURL":"",
-// "address":"",
-// "log":"stdout",
-// "database":"./database.db",
-// "root":"/srv",
-// "disable-thumbnails":false,
-// "disable-preview-resize":false,
-// "disable-exec":false,
-// "disable-type-detection-by-header":false
-// },
-// "auth":{
-// "header":"",
-// "method":"",
-// "command":"",
-// "signup":false,
-// "shell":""
-// },
-// "branding":{
-// "name":"",
-// "color":"",
-// "files":"",
-// "disableExternal":"",
-// "disableUsedPercentage":""
-// },
-// "permissions":{
-// "Admin":false,
-// "Execute":true,
-// "Create":true,
-// "Rename":true,
-// "Modify":true,
-// "Delete":true,
-// "Share":true,
-// "Download":true
-// },
-// "commands":{},
-// "shell":{},
-// "rules":{}
-// }
diff --git a/backend/settings/testingConfig.yaml b/backend/settings/testingConfig.yaml
new file mode 100644
index 00000000..f2dd121d
--- /dev/null
+++ b/backend/settings/testingConfig.yaml
@@ -0,0 +1,52 @@
+server:
+ indexingInterval: 5
+ numImageProcessors: 4
+ socket: ""
+ tlsKey: ""
+ tlsCert: ""
+ enableThumbnails: false
+ resizePreview: true
+ typeDetectionByHeader: true
+ port: 8080
+ baseURL: "/"
+ address: ""
+ log: "stdout"
+ database: "database.db"
+ root: "/srv"
+auth:
+ recaptcha:
+ host: ""
+ key: ""
+ secret: ""
+ header: ""
+ method: json
+ command: ""
+ signup: false
+ shell: ""
+frontend:
+ name: ""
+ disableExternal: false
+ disableUsedPercentage: true
+ files: ""
+ theme: ""
+ color: ""
+userDefaults:
+ scope: ""
+ locale: ""
+ viewMode: ""
+ singleClick: true
+ sorting:
+ by: ""
+ asc: true
+ perm:
+ admin: true
+ execute: true
+ create: true
+ rename: true
+ modify: true
+ delete: true
+ share: true
+ download: true
+ commands: []
+ hideDotfiles: false
+ dateFormat: false
diff --git a/backend/storage/bolt/importer/conf.go b/backend/storage/bolt/importer/conf.go
deleted file mode 100644
index a6d84a21..00000000
--- a/backend/storage/bolt/importer/conf.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package importer
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "os"
- "path/filepath"
-
- "github.com/asdine/storm/v3"
- "github.com/pelletier/go-toml/v2"
- "gopkg.in/yaml.v2"
-
- "github.com/gtsteffaniak/filebrowser/auth"
- "github.com/gtsteffaniak/filebrowser/settings"
- "github.com/gtsteffaniak/filebrowser/storage"
- "github.com/gtsteffaniak/filebrowser/users"
-)
-
-type oldDefs struct {
- Commands []string `json:"commands" yaml:"commands" toml:"commands"`
- Scope string `json:"scope" yaml:"scope" toml:"scope"`
- ViewMode string `json:"viewMode" yaml:"viewMode" toml:"viewMode"`
- Locale string `json:"locale" yaml:"locale" toml:"locale"`
- AllowCommands bool `json:"allowCommands" yaml:"allowCommands" toml:"allowCommands"`
- AllowEdit bool `json:"allowEdit" yaml:"allowEdit" toml:"allowEdit"`
- AllowNew bool `json:"allowNew" yaml:"allowNew" toml:"allowNew"`
-}
-
-type oldAuth struct {
- Method string `json:"method" yaml:"method" toml:"method"` // default none proxy
- Header string `json:"header" yaml:"header" toml:"header"`
- Command string `json:"command" yaml:"command" toml:"command"`
-}
-
-type oldConf struct {
- Port string `json:"port" yaml:"port" toml:"port"`
- BaseURL string `json:"baseURL" yaml:"baseURL" toml:"baseURL"`
- Log string `json:"log" yaml:"log" toml:"log"`
- Address string `json:"address" yaml:"address" toml:"address"`
- Defaults oldDefs `json:"defaults" yaml:"defaults" toml:"defaults"`
- ReCaptcha struct {
- Key string `json:"key" yaml:"key" toml:"key"`
- Secret string `json:"secret" yaml:"secret" toml:"secret"`
- Host string `json:"host" yaml:"host" toml:"host"`
- } `json:"recaptcha" yaml:"recaptcha" toml:"recaptcha"`
- Auth oldAuth `json:"auth" yaml:"auth" toml:"auth"`
-}
-
-var defaults = &oldConf{
- Port: "0",
- Log: "stdout",
- Defaults: oldDefs{
- Commands: []string{"git", "svn", "hg"},
- ViewMode: string(users.MosaicViewMode),
- AllowCommands: true,
- AllowEdit: true,
- AllowNew: true,
- Locale: "en",
- },
- Auth: oldAuth{
- Method: "default",
- },
-}
-
-func readConf(path string) (*oldConf, error) {
- cfg := &oldConf{}
- if path != "" {
- ext := filepath.Ext(path)
-
- fd, err := os.Open(path)
- if err != nil {
- return nil, err
- }
- defer fd.Close()
-
- switch ext {
- case ".json":
- err = json.NewDecoder(fd).Decode(cfg)
- case ".toml":
- err = toml.NewDecoder(fd).Decode(cfg)
- case ".yaml", ".yml":
- err = yaml.NewDecoder(fd).Decode(cfg)
- default:
- return nil, errors.New("unsupported config extension " + ext)
- }
-
- if err != nil {
- return nil, err
- }
- } else {
- cfg = defaults
- path, err := filepath.Abs(".")
- if err != nil {
- return nil, err
- }
- cfg.Defaults.Scope = path
- }
- return cfg, nil
-}
-
-func importConf(db *storm.DB, path string, sto *storage.Storage) error {
- cfg, err := readConf(path)
- if err != nil {
- return err
- }
-
- commands := map[string][]string{}
- err = db.Get("config", "commands", &commands)
- if err != nil {
- return err
- }
-
- key := []byte{}
- err = db.Get("config", "key", &key)
- if err != nil {
- return err
- }
-
- s := &settings.Settings{
- Key: key,
- Signup: false,
- Defaults: settings.UserDefaults{
- Scope: cfg.Defaults.Scope,
- Commands: cfg.Defaults.Commands,
- ViewMode: users.ViewMode(cfg.Defaults.ViewMode),
- Locale: cfg.Defaults.Locale,
- Perm: users.Permissions{
- Admin: false,
- Execute: cfg.Defaults.AllowCommands,
- Create: cfg.Defaults.AllowNew,
- Rename: cfg.Defaults.AllowEdit,
- Modify: cfg.Defaults.AllowEdit,
- Delete: cfg.Defaults.AllowEdit,
- Share: true,
- Download: true,
- },
- },
- }
-
- server := &settings.Server{
- BaseURL: cfg.BaseURL,
- Port: 8080,
- Address: cfg.Address,
- Log: cfg.Log,
- }
- fmt.Println("config.go", server)
- var auther auth.Auther
- switch cfg.Auth.Method {
- case "proxy":
- auther = &auth.ProxyAuth{Header: cfg.Auth.Header}
- s.Auth.Method = "proxy"
- case "hook":
- auther = &auth.HookAuth{Command: cfg.Auth.Command}
- s.Auth.Method = "hoook"
- case "none":
- auther = &auth.NoAuth{}
- s.Auth.Method = "noauth"
- default:
- auther = &auth.JSONAuth{
- ReCaptcha: &auth.ReCaptcha{
- Host: cfg.ReCaptcha.Host,
- Key: cfg.ReCaptcha.Key,
- Secret: cfg.ReCaptcha.Secret,
- },
- }
- s.Auth.Method = "password"
- }
-
- err = sto.Auth.Save(auther)
- if err != nil {
- return err
- }
-
- err = sto.Settings.Save(s)
- if err != nil {
- return err
- }
-
- err = sto.Settings.SaveServer(server)
- if err != nil {
- return err
- }
-
- fmt.Println("Configuration successfully imported.")
- return nil
-}
diff --git a/backend/storage/bolt/importer/importer.go b/backend/storage/bolt/importer/importer.go
deleted file mode 100644
index 36b60283..00000000
--- a/backend/storage/bolt/importer/importer.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package importer
-
-import (
- "github.com/asdine/storm/v3"
- "log"
-
- "github.com/gtsteffaniak/filebrowser/storage/bolt"
-)
-
-// Import imports an old configuration to a newer database.
-func Import(oldDBPath, oldConf, newDBPath string) error {
- log.Println(oldDBPath, oldConf, newDBPath)
- oldDB, err := storm.Open(oldDBPath)
- if err != nil {
- return err
- }
- defer oldDB.Close()
-
- newDB, err := storm.Open(newDBPath)
- if err != nil {
- return err
- }
- defer newDB.Close()
-
- sto, err := bolt.NewStorage(newDB)
- if err != nil {
- return err
- }
-
- err = importUsers(oldDB, sto)
- if err != nil {
- return err
- }
-
- err = importConf(oldDB, oldConf, sto)
- if err != nil {
- return err
- }
-
- return err
-}
diff --git a/backend/storage/bolt/importer/users.go b/backend/storage/bolt/importer/users.go
deleted file mode 100644
index 4606fc2e..00000000
--- a/backend/storage/bolt/importer/users.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package importer
-
-import (
- "encoding/json"
- "fmt"
-
- "github.com/asdine/storm/v3"
- bolt "go.etcd.io/bbolt"
-
- "github.com/gtsteffaniak/filebrowser/rules"
- "github.com/gtsteffaniak/filebrowser/storage"
- "github.com/gtsteffaniak/filebrowser/users"
-)
-
-type oldUser struct {
- ID int `storm:"id,increment"`
- Admin bool `json:"admin"`
- AllowCommands bool `json:"allowCommands"` // Execute commands
- AllowEdit bool `json:"allowEdit"` // Edit/rename files
- AllowNew bool `json:"allowNew"` // Create files and folders
- AllowPublish bool `json:"allowPublish"` // Publish content (to use with static gen)
- LockPassword bool `json:"lockPassword"`
- Commands []string `json:"commands"`
- Locale string `json:"locale"`
- Password string `json:"password"`
- Rules []*rules.Rule `json:"rules"`
- Scope string `json:"filesystem"`
- Username string `json:"username" storm:"index,unique"`
- ViewMode string `json:"viewMode"`
-}
-
-func readOldUsers(db *storm.DB) ([]*oldUser, error) {
- var oldUsers []*oldUser
- err := db.Bolt.View(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("User")).ForEach(func(k []byte, v []byte) error {
- if len(v) > 0 && string(v)[0] == '{' {
- user := &oldUser{}
- err := json.Unmarshal(v, user)
-
- if err != nil {
- return err
- }
-
- oldUsers = append(oldUsers, user)
- }
-
- return nil
- })
- })
-
- return oldUsers, err
-}
-
-func convertUsersToNew(old []*oldUser) ([]*users.User, error) {
- list := []*users.User{}
-
- for _, oldUser := range old {
- user := &users.User{
- Username: oldUser.Username,
- Password: oldUser.Password,
- Scope: oldUser.Scope,
- Locale: oldUser.Locale,
- LockPassword: oldUser.LockPassword,
- ViewMode: users.ViewMode(oldUser.ViewMode),
- Commands: oldUser.Commands,
- Rules: []rules.Rule{},
- Perm: users.Permissions{
- Admin: oldUser.Admin,
- Execute: oldUser.AllowCommands,
- Create: oldUser.AllowNew,
- Rename: oldUser.AllowEdit,
- Modify: oldUser.AllowEdit,
- Delete: oldUser.AllowEdit,
- Share: true,
- Download: true,
- },
- }
-
- for _, rule := range oldUser.Rules {
- user.Rules = append(user.Rules, *rule)
- }
-
- err := user.Clean("")
- if err != nil {
- return nil, err
- }
-
- list = append(list, user)
- }
-
- return list, nil
-}
-
-func importUsers(old *storm.DB, sto *storage.Storage) error {
- oldUsers, err := readOldUsers(old)
- if err != nil {
- return err
- }
-
- newUsers, err := convertUsersToNew(oldUsers)
- if err != nil {
- return err
- }
-
- for _, user := range newUsers {
- err = sto.Users.Save(user)
- if err != nil {
- return err
- }
- }
-
- fmt.Printf("%d users successfully imported into the new DB.\n", len(newUsers))
- return nil
-}
diff --git a/backend/storage/bolt/utils.go b/backend/storage/bolt/utils.go
index fa84e3c3..f0cc6253 100644
--- a/backend/storage/bolt/utils.go
+++ b/backend/storage/bolt/utils.go
@@ -1,12 +1,15 @@
package bolt
import (
+ "log"
+
"github.com/asdine/storm/v3"
"github.com/gtsteffaniak/filebrowser/errors"
)
func get(db *storm.DB, name string, to interface{}) error {
+ log.Printf("name, %v , to %#v", name, to)
err := db.Get("config", name, to)
if err == storm.ErrNotFound {
return errors.ErrNotExist
@@ -16,5 +19,6 @@ func get(db *storm.DB, name string, to interface{}) error {
}
func save(db *storm.DB, name string, from interface{}) error {
+ log.Printf("name, %v , from %#v", name, from)
return db.Set("config", name, from)
}
diff --git a/backend/test_output.txt b/backend/test_output.txt
new file mode 100644
index 00000000..42fde92b
--- /dev/null
+++ b/backend/test_output.txt
@@ -0,0 +1,113 @@
+
+ == Running tests ==
+/usr/local/go/bin/go
+? github.com/gtsteffaniak/filebrowser [no test files]
+? github.com/gtsteffaniak/filebrowser/auth [no test files]
+? github.com/gtsteffaniak/filebrowser/cmd [no test files]
+? github.com/gtsteffaniak/filebrowser/errors [no test files]
+? github.com/gtsteffaniak/filebrowser/files [no test files]
+=== RUN TestFileCache
+--- PASS: TestFileCache (0.00s)
+PASS
+ok github.com/gtsteffaniak/filebrowser/diskcache (cached)
+=== RUN TestCommonPrefix
+=== RUN TestCommonPrefix/sub_folder
+=== RUN TestCommonPrefix/relative_path
+=== RUN TestCommonPrefix/no_common_path
+=== RUN TestCommonPrefix/same_lvl
+--- PASS: TestCommonPrefix (0.00s)
+ --- PASS: TestCommonPrefix/sub_folder (0.00s)
+ --- PASS: TestCommonPrefix/relative_path (0.00s)
+ --- PASS: TestCommonPrefix/no_common_path (0.00s)
+ --- PASS: TestCommonPrefix/same_lvl (0.00s)
+PASS
+ok github.com/gtsteffaniak/filebrowser/fileutils (cached)
+? github.com/gtsteffaniak/filebrowser/settings [no test files]
+? github.com/gtsteffaniak/filebrowser/share [no test files]
+? github.com/gtsteffaniak/filebrowser/storage [no test files]
+? github.com/gtsteffaniak/filebrowser/storage/bolt [no test files]
+2023/09/02 13:07:17 Error opening YAML file: open filebrowser.yaml: no such file or directory
+FAIL github.com/gtsteffaniak/filebrowser/http 0.008s
+=== RUN TestService_Resize
+=== RUN TestService_Resize/convert_to_png
+=== RUN TestService_Resize/convert_to_tiff
+=== RUN TestService_Resize/resize_bmp
+=== RUN TestService_Resize/resize_with_medium_quality
+=== RUN TestService_Resize/resize_with_low_quality
+=== RUN TestService_Resize/get_thumbnail_from_file_with_APP0_JFIF
+=== RUN TestService_Resize/fill_upscale
+=== RUN TestService_Resize/fit_upscale
+=== RUN TestService_Resize/convert_to_gif
+=== RUN TestService_Resize/convert_to_bmp
+=== RUN TestService_Resize/resize_tiff
+=== RUN TestService_Resize/resize_with_high_quality
+=== RUN TestService_Resize/fill_downscale
+=== RUN TestService_Resize/keep_original_format
+=== RUN TestService_Resize/convert_to_unknown
+=== RUN TestService_Resize/get_thumbnail_from_file_without_APP0_JFIF
+=== RUN TestService_Resize/resize_for_higher_quality_levels
+=== RUN TestService_Resize/broken_file
+=== RUN TestService_Resize/fit_downscale
+=== RUN TestService_Resize/convert_to_jpeg
+=== RUN TestService_Resize/resize_png
+=== RUN TestService_Resize/resize_gif
+=== RUN TestService_Resize/resize_with_unknown_quality
+=== RUN TestService_Resize/resize_from_file_without_IFD1_thumbnail
+--- PASS: TestService_Resize (1.36s)
+ --- PASS: TestService_Resize/convert_to_png (0.01s)
+ --- PASS: TestService_Resize/convert_to_tiff (0.01s)
+ --- PASS: TestService_Resize/resize_bmp (0.01s)
+ --- PASS: TestService_Resize/resize_with_medium_quality (0.01s)
+ --- PASS: TestService_Resize/resize_with_low_quality (0.01s)
+ --- PASS: TestService_Resize/get_thumbnail_from_file_with_APP0_JFIF (0.02s)
+ --- PASS: TestService_Resize/fill_upscale (0.01s)
+ --- PASS: TestService_Resize/fit_upscale (0.00s)
+ --- PASS: TestService_Resize/convert_to_gif (0.01s)
+ --- PASS: TestService_Resize/convert_to_bmp (0.01s)
+ --- PASS: TestService_Resize/resize_tiff (0.01s)
+ --- PASS: TestService_Resize/resize_with_high_quality (0.01s)
+ --- PASS: TestService_Resize/fill_downscale (0.01s)
+ --- PASS: TestService_Resize/keep_original_format (0.01s)
+ --- PASS: TestService_Resize/convert_to_unknown (0.01s)
+ --- PASS: TestService_Resize/get_thumbnail_from_file_without_APP0_JFIF (0.03s)
+ --- PASS: TestService_Resize/resize_for_higher_quality_levels (0.03s)
+ --- PASS: TestService_Resize/broken_file (0.00s)
+ --- PASS: TestService_Resize/fit_downscale (0.01s)
+ --- PASS: TestService_Resize/convert_to_jpeg (0.01s)
+ --- PASS: TestService_Resize/resize_png (0.02s)
+ --- PASS: TestService_Resize/resize_gif (0.02s)
+ --- PASS: TestService_Resize/resize_with_unknown_quality (0.01s)
+ --- PASS: TestService_Resize/resize_from_file_without_IFD1_thumbnail (1.09s)
+=== RUN TestService_FormatFromExtension
+=== RUN TestService_FormatFromExtension/gif
+=== RUN TestService_FormatFromExtension/tiff
+=== RUN TestService_FormatFromExtension/bmp
+=== RUN TestService_FormatFromExtension/unknown
+=== RUN TestService_FormatFromExtension/jpg
+=== RUN TestService_FormatFromExtension/jpeg
+=== RUN TestService_FormatFromExtension/png
+--- PASS: TestService_FormatFromExtension (0.00s)
+ --- PASS: TestService_FormatFromExtension/gif (0.00s)
+ --- PASS: TestService_FormatFromExtension/tiff (0.00s)
+ --- PASS: TestService_FormatFromExtension/bmp (0.00s)
+ --- PASS: TestService_FormatFromExtension/unknown (0.00s)
+ --- PASS: TestService_FormatFromExtension/jpg (0.00s)
+ --- PASS: TestService_FormatFromExtension/jpeg (0.00s)
+ --- PASS: TestService_FormatFromExtension/png (0.00s)
+PASS
+ok github.com/gtsteffaniak/filebrowser/img (cached)
+=== RUN TestMatchHidden
+--- PASS: TestMatchHidden (0.00s)
+PASS
+ok github.com/gtsteffaniak/filebrowser/rules (cached)
+2023/09/02 13:07:17 Error opening YAML file: open filebrowser.yaml: no such file or directory
+FAIL github.com/gtsteffaniak/filebrowser/runner 0.007s
+=== RUN TestParseSearch
+--- PASS: TestParseSearch (0.00s)
+PASS
+ok github.com/gtsteffaniak/filebrowser/search (cached)
+? github.com/gtsteffaniak/filebrowser/version [no test files]
+testing: warning: no tests to run
+PASS
+ok github.com/gtsteffaniak/filebrowser/users (cached) [no tests to run]
+FAIL
diff --git a/backend/users/users.go b/backend/users/users.go
index 91dcea68..cfdcb2fa 100644
--- a/backend/users/users.go
+++ b/backend/users/users.go
@@ -11,12 +11,9 @@ import (
"github.com/gtsteffaniak/filebrowser/rules"
)
-// ViewMode describes a view mode.
-type ViewMode string
-
-const (
- ListViewMode ViewMode = "list"
- MosaicViewMode ViewMode = "mosaic"
+var (
+ ListViewMode = "list"
+ MosaicViewMode = "mosaic"
)
// User describes a user.
@@ -27,7 +24,7 @@ type User struct {
Scope string `json:"scope"`
Locale string `json:"locale"`
LockPassword bool `json:"lockPassword"`
- ViewMode ViewMode `json:"viewMode"`
+ ViewMode string `json:"viewMode"`
SingleClick bool `json:"singleClick"`
Perm Permissions `json:"perm"`
Commands []string `json:"commands"`
diff --git a/frontend/src/views/settings/Global.vue b/frontend/src/views/settings/Global.vue
index 3807dab6..ff1618f7 100644
--- a/frontend/src/views/settings/Global.vue
+++ b/frontend/src/views/settings/Global.vue
@@ -56,7 +56,7 @@
{{ $t("settings.disableExternalLinks") }}
@@ -65,7 +65,7 @@
{{ $t("settings.disableUsedDiskPercentage") }}
@@ -75,7 +75,7 @@
@@ -85,7 +85,7 @@
@@ -97,7 +97,7 @@
diff --git a/test_output.txt b/test_output.txt
new file mode 100644
index 00000000..e69de29b