From d0cca8f285e635631b07b890480d3b501c673a0a Mon Sep 17 00:00:00 2001 From: Graham Steffaniak Date: Fri, 1 Sep 2023 09:00:02 -0500 Subject: [PATCH] updated auth method --- backend/.filebrowser.json | 8 ++ backend/cmd/config.go | 57 +++----- backend/cmd/config_cat.go | 2 +- backend/cmd/config_export.go | 2 +- backend/cmd/config_import.go | 3 +- backend/cmd/config_init.go | 32 +---- backend/cmd/config_set.go | 32 ++--- backend/cmd/root.go | 162 ++++------------------ backend/filebrowser.yml | 12 +- backend/go.mod | 5 + backend/go.sum | 19 +++ backend/http/auth.go | 2 +- backend/http/settings.go | 6 +- backend/http/static.go | 32 ++--- backend/settings/config.go | 50 +++++++ backend/settings/settings.go | 4 + backend/settings/structs.go | 32 +++-- backend/storage/bolt/config.go | 6 +- backend/storage/bolt/importer/conf.go | 10 +- backend/storage/bolt/importer/importer.go | 2 + 20 files changed, 206 insertions(+), 272 deletions(-) create mode 100644 backend/.filebrowser.json create mode 100644 backend/settings/config.go diff --git a/backend/.filebrowser.json b/backend/.filebrowser.json new file mode 100644 index 00000000..40e89fbb --- /dev/null +++ b/backend/.filebrowser.json @@ -0,0 +1,8 @@ +{ + "port": 5555, + "baseURL": "", + "address": "", + "log": "stdout", + "database": "./database.db", + "root": "/srv" +} \ No newline at end of file diff --git a/backend/cmd/config.go b/backend/cmd/config.go index b93563b9..a8d9211d 100644 --- a/backend/cmd/config.go +++ b/backend/cmd/config.go @@ -28,7 +28,6 @@ var configCmd = &cobra.Command{ } func addConfigFlags(flags *pflag.FlagSet) { - addServerFlags(flags) addUserFlags(flags) flags.BoolP("signup", "s", false, "allow users to signup") flags.String("shell", "", "shell command to which other commands should be appended") @@ -41,38 +40,20 @@ func addConfigFlags(flags *pflag.FlagSet) { flags.String("recaptcha.key", "", "ReCaptcha site key") flags.String("recaptcha.secret", "", "ReCaptcha secret") - flags.String("branding.name", "", "replace 'File Browser' by this name") - flags.String("branding.color", "", "set the theme color") - flags.String("branding.files", "", "path to directory with images and custom styles") - flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links") - flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph") + 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(flags *pflag.FlagSet, defaults ...interface{}) (string, auth.Auther) { - method := mustGetString(flags, "auth.method") - +func getAuthentication() (string, auth.Auther) { + method := settings.GlobalConfiguration.Auth.Method var defaultAuther map[string]interface{} - if len(defaults) > 0 { - if hasAuth := defaults[0]; hasAuth != true { - for _, arg := range defaults { - switch def := arg.(type) { - case *settings.Settings: - method = def.AuthMethod - case auth.Auther: - ms, err := json.Marshal(def) - checkErr(err) - err = json.Unmarshal(ms, &defaultAuther) - checkErr(err) - } - } - } - } - var auther auth.Auther if method == auth.MethodProxyAuth { - header := mustGetString(flags, "auth.header") - + header := settings.GlobalConfiguration.Auth.Header if header == "" { header = defaultAuther["header"].(string) } @@ -90,9 +71,9 @@ func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (string, a if method == auth.MethodJSONAuth { jsonAuth := &auth.JSONAuth{} - host := mustGetString(flags, "recaptcha.host") - key := mustGetString(flags, "recaptcha.key") - secret := mustGetString(flags, "recaptcha.secret") + 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 { @@ -117,7 +98,7 @@ func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (string, a } if method == auth.MethodHookAuth { - command := mustGetString(flags, "auth.command") + command := settings.GlobalConfiguration.Auth.Command if command == "" { command = defaultAuther["command"].(string) @@ -142,14 +123,14 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut 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.AuthMethod) + 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, "\nBranding:") - fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name) - fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files) - fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal) - fmt.Fprintf(w, "\tDisable used disk percentage graph:\t%t\n", set.Branding.DisableUsedPercentage) - fmt.Fprintf(w, "\tColor:\t%s\n", set.Branding.Color) + 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) diff --git a/backend/cmd/config_cat.go b/backend/cmd/config_cat.go index eca56dd1..3f06eb9f 100644 --- a/backend/cmd/config_cat.go +++ b/backend/cmd/config_cat.go @@ -18,7 +18,7 @@ var configCatCmd = &cobra.Command{ checkErr(err) ser, err := d.store.Settings.GetServer() checkErr(err) - auther, err := d.store.Auth.Get(set.AuthMethod) + 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 index 9d6450f9..a4d8ecff 100644 --- a/backend/cmd/config_export.go +++ b/backend/cmd/config_export.go @@ -22,7 +22,7 @@ and imported again with 'config import' command.`, server, err := d.store.Settings.GetServer() checkErr(err) - auther, err := d.store.Auth.Get(settings.AuthMethod) + auther, err := d.store.Auth.Get(settings.Auth.Method) checkErr(err) data := &settingsFile{ diff --git a/backend/cmd/config_import.go b/backend/cmd/config_import.go index 98309612..800b0512 100644 --- a/backend/cmd/config_import.go +++ b/backend/cmd/config_import.go @@ -43,7 +43,6 @@ The path must be for a json or yaml file.`, } else { key = generateKey() } - file := settingsFile{} err := unmarshal(args[0], &file) checkErr(err) @@ -63,7 +62,7 @@ The path must be for a json or yaml file.`, } var auther auth.Auther - switch file.Settings.AuthMethod { + switch file.Settings.Auth.Method { case auth.MethodJSONAuth: auther = getAuther(auth.JSONAuth{}, rawAuther).(*auth.JSONAuth) case auth.MethodNoAuth: diff --git a/backend/cmd/config_init.go b/backend/cmd/config_init.go index 4f3b4050..47bf8df7 100644 --- a/backend/cmd/config_init.go +++ b/backend/cmd/config_init.go @@ -26,33 +26,9 @@ override the options.`, defaults := settings.UserDefaults{} flags := cmd.Flags() getUserDefaults(flags, &defaults, true) - authMethod, auther := getAuthentication(flags) - - s := &settings.Settings{ - Key: generateKey(), - Signup: mustGetBool(flags, "signup"), - Shell: convertCmdStrToCmdArray(mustGetString(flags, "shell")), - AuthMethod: authMethod, - Defaults: defaults, - Branding: settings.Branding{ - Name: mustGetString(flags, "branding.name"), - DisableExternal: mustGetBool(flags, "branding.disableExternal"), - DisableUsedPercentage: mustGetBool(flags, "branding.DisableUsedPercentage"), - Files: mustGetString(flags, "branding.files"), - }, - } - - ser := &settings.Server{ - Address: mustGetString(flags, "address"), - Socket: mustGetString(flags, "socket"), - Root: mustGetString(flags, "root"), - BaseURL: mustGetString(flags, "baseurl"), - TLSKey: mustGetString(flags, "key"), - TLSCert: mustGetString(flags, "cert"), - Port: mustGetString(flags, "port"), - Log: mustGetString(flags, "log"), - } - err := d.store.Settings.Save(s) + _, auther := getAuthentication() + ser := &settings.GlobalConfiguration.Server + err := d.store.Settings.Save(&settings.GlobalConfiguration) checkErr(err) err = d.store.Settings.SaveServer(ser) checkErr(err) @@ -64,6 +40,6 @@ 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, s, auther) + printSettings(ser, &settings.GlobalConfiguration, auther) }, pythonConfig{noDB: true}), } diff --git a/backend/cmd/config_set.go b/backend/cmd/config_set.go index 5a02288f..d7bb80d9 100644 --- a/backend/cmd/config_set.go +++ b/backend/cmd/config_set.go @@ -24,7 +24,6 @@ you want to change. Other options will remain unchanged.`, ser, err := d.store.Settings.GetServer() checkErr(err) - hasAuth := false flags.Visit(func(flag *pflag.Flag) { switch flag.Name { case "baseurl": @@ -40,37 +39,30 @@ you want to change. Other options will remain unchanged.`, case "address": ser.Address = mustGetString(flags, flag.Name) case "port": - ser.Port = mustGetString(flags, flag.Name) + ser.Port = 8080 case "log": ser.Log = mustGetString(flags, flag.Name) case "signup": set.Signup = mustGetBool(flags, flag.Name) - case "auth.method": - hasAuth = true case "shell": set.Shell = convertCmdStrToCmdArray(mustGetString(flags, flag.Name)) - case "branding.name": - set.Branding.Name = mustGetString(flags, flag.Name) - case "branding.color": - set.Branding.Color = mustGetString(flags, flag.Name) - case "branding.disableExternal": - set.Branding.DisableExternal = mustGetBool(flags, flag.Name) - case "branding.disableUsedPercentage": - set.Branding.DisableUsedPercentage = mustGetBool(flags, flag.Name) - case "branding.files": - set.Branding.Files = 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, err := d.store.Auth.Get(set.AuthMethod) - checkErr(err) - - // check if there are new flags for existing auth method - set.AuthMethod, auther = getAuthentication(flags, hasAuth, set, auther) - + _, auther := getAuthentication() err = d.store.Auth.Save(auther) checkErr(err) err = d.store.Settings.Save(set) diff --git a/backend/cmd/root.go b/backend/cmd/root.go index 9191df22..ca31422d 100644 --- a/backend/cmd/root.go +++ b/backend/cmd/root.go @@ -2,7 +2,6 @@ package cmd import ( "crypto/tls" - "errors" "io" "io/fs" "log" @@ -10,7 +9,6 @@ import ( "net/http" "os" "os/signal" - "path/filepath" "strconv" "strings" "syscall" @@ -57,55 +55,19 @@ func init() { flags.Bool("noauth", false, "use the noauth auther when using quick setup") flags.String("username", "admin", "username for the first user when using quick config") flags.String("password", "", "hashed password for the first user when using quick config (default \"admin\")") - - addServerFlags(flags) -} - -func getEnvVariableAsUint32(key string) uint32 { - valueStr := os.Getenv(key) - value, err := strconv.ParseUint(valueStr, 10, 32) - if err != nil { - return 5 // default value every 5 minutes - } - return uint32(value) -} - -func addServerFlags(flags *pflag.FlagSet) { - flags.StringP("address", "a", "127.0.0.1", "address to listen on") - flags.StringP("log", "l", "stdout", "log output") - flags.StringP("port", "p", "8080", "port to listen on") - flags.StringP("cert", "t", "", "tls certificate") - flags.StringP("key", "k", "", "tls key") - flags.StringP("root", "r", ".", "root to prepend to relative paths") - flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)") - flags.Uint32("socket-perm", 0666, "unix socket file permissions") //nolint:gomnd - flags.StringP("baseurl", "b", "", "base url") - flags.String("cache-dir", "", "file cache directory (disabled if empty)") - flags.Int("img-processors", 4, "image processors count") //nolint:gomnd - flags.Bool("disable-thumbnails", false, "disable image thumbnails") - flags.Bool("disable-preview-resize", true, "disable resize of image previews") - flags.Bool("disable-exec", false, "disables Command Runner feature") - flags.Bool("disable-type-detection-by-header", false, "disables type detection by reading file headers") } var rootCmd = &cobra.Command{ Use: "filebrowser", Short: "A stylish web-based file browser", - Long: `File Browser CLI lets you create the database to use with File Browser, -manage your users and all the configurations without acessing the -web interface. - + Long: ` If you've never run File Browser, you'll need to have a database for it. Don't worry: you don't need to setup a separate database server. We're using Bolt DB which is a single file database and all managed by ourselves. -For this specific command, all the flags you have available (except -"config" for the configuration file), can be given either through -environment variables or configuration files. - If you don't set "config", it will look for a configuration file called -.filebrowser.{json, toml, yaml, yml} in the following directories: +filebrowser.{json, toml, yaml, yml} in the following directories: - ./ - $HOME/ @@ -119,70 +81,60 @@ The precedence of the configuration values are as follows: - database values - defaults -The environment variables are prefixed by "FB_" followed by the option -name in caps. So to set "database" via an env variable, you should -set FB_DATABASE. - Also, if the database path doesn't exist, File Browser will enter into the quick setup mode and a new database will be bootstraped and a new user created with the credentials from options "username" and "password".`, Run: python(func(cmd *cobra.Command, args []string, d pythonData) { + settings.Initialize() + serverConfig := settings.GlobalConfiguration.Server log.Println(cfgFile) if !d.hadDB { quickSetup(cmd.Flags(), d) } - // build img service - workersCount, err := cmd.Flags().GetInt("img-processors") - checkErr(err) + workersCount := serverConfig.NumImageProcessors if workersCount < 1 { log.Fatal("Image resize workers count could not be < 1") } imgSvc := img.New(workersCount) var fileCache diskcache.Interface = diskcache.NewNoOp() - cacheDir, err := cmd.Flags().GetString("cache-dir") - checkErr(err) + cacheDir := "/tmp" if cacheDir != "" { if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet,gomnd log.Fatalf("can't make directory %s: %s", cacheDir, err) } fileCache = diskcache.New(afero.NewOsFs(), cacheDir) } + // initialize indexing and schedule indexing ever n minutes (default 5) - indexingInterval := getEnvVariableAsUint32("INDEXING_INTERVAL") - go search.InitializeIndex(indexingInterval) + go search.InitializeIndex(serverConfig.IndexingInterval) - server := getRunParams(cmd.Flags(), d.store) - setupLog(server.Log) - - root, err := filepath.Abs(server.Root) + _, err := os.Stat(serverConfig.Root) checkErr(err) - server.Root = root - - adr := server.Address + ":" + server.Port var listener net.Listener + address := serverConfig.Address+":"+strconv.Itoa(serverConfig.Port) switch { - case server.Socket != "": - listener, err = net.Listen("unix", server.Socket) + case serverConfig.Socket != "": + listener, err = net.Listen("unix", serverConfig.Socket) checkErr(err) socketPerm, err := cmd.Flags().GetUint32("socket-perm") //nolint:govet checkErr(err) - err = os.Chmod(server.Socket, os.FileMode(socketPerm)) + err = os.Chmod(serverConfig.Socket, os.FileMode(socketPerm)) checkErr(err) - case server.TLSKey != "" && server.TLSCert != "": - cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:govet + case serverConfig.TLSKey != "" && serverConfig.TLSCert != "": + cer, err := tls.LoadX509KeyPair(serverConfig.TLSCert, serverConfig.TLSKey) //nolint:govet checkErr(err) - listener, err = tls.Listen("tcp", adr, &tls.Config{ + listener, err = tls.Listen("tcp", address, &tls.Config{ MinVersion: tls.VersionTLS12, Certificates: []tls.Certificate{cer}}, ) checkErr(err) default: - listener, err = net.Listen("tcp", adr) + listener, err = net.Listen("tcp", address) checkErr(err) } @@ -191,7 +143,7 @@ user created with the credentials from options "username" and "password".`, go cleanupHandler(listener, sigc) assetsFs := dirFS{Dir: http.Dir("frontend/dist")} - handler, err := fbhttp.NewHandler(imgSvc, fileCache, d.store, server, assetsFs) + handler, err := fbhttp.NewHandler(imgSvc, fileCache, d.store, &serverConfig, assetsFs) checkErr(err) defer listener.Close() @@ -215,68 +167,6 @@ func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfac func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server { server, err := st.Settings.GetServer() checkErr(err) - - if val, set := getParamB(flags, "root"); set { - server.Root = val - } - - if val, set := getParamB(flags, "baseurl"); set { - server.BaseURL = val - } - - if val, set := getParamB(flags, "log"); set { - server.Log = val - } - - isSocketSet := false - isAddrSet := false - - if val, set := getParamB(flags, "address"); set { - server.Address = val - isAddrSet = isAddrSet || set - } - - if val, set := getParamB(flags, "port"); set { - server.Port = val - isAddrSet = isAddrSet || set - } - - if val, set := getParamB(flags, "key"); set { - server.TLSKey = val - isAddrSet = isAddrSet || set - } - - if val, set := getParamB(flags, "cert"); set { - server.TLSCert = val - isAddrSet = isAddrSet || set - } - - if val, set := getParamB(flags, "socket"); set { - server.Socket = val - isSocketSet = isSocketSet || set - } - - if isAddrSet && isSocketSet { - checkErr(errors.New("--socket flag cannot be used with --address, --port, --key nor --cert")) - } - - // Do not use saved Socket if address was manually set. - if isAddrSet && server.Socket != "" { - server.Socket = "" - } - - _, disableThumbnails := getParamB(flags, "disable-thumbnails") - server.EnableThumbnails = !disableThumbnails - - _, disablePreviewResize := getParamB(flags, "disable-preview-resize") - server.ResizePreview = !disablePreviewResize - - _, disableTypeDetectionByHeader := getParamB(flags, "disable-type-detection-by-header") - server.TypeDetectionByHeader = !disableTypeDetectionByHeader - - _, disableExec := getParamB(flags, "disable-exec") - server.EnableExec = !disableExec - return server } @@ -348,32 +238,28 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) { Download: true, }, }, - AuthMethod: "", - Branding: settings.Branding{}, + Frontend: settings.Frontend{}, Commands: nil, Shell: nil, Rules: nil, } var err error - if _, noauth := getParamB(flags, "noauth"); noauth { - set.AuthMethod = auth.MethodNoAuth + if settings.GlobalConfiguration.Auth.Method == "noAuth" { + set.Auth.Method = "noAuth" err = d.store.Auth.Save(&auth.NoAuth{}) - } else { - set.AuthMethod = auth.MethodJSONAuth + }else{ + set.Auth.Method = auth.MethodJSONAuth err = d.store.Auth.Save(&auth.JSONAuth{}) } - err = d.store.Settings.Save(set) checkErr(err) ser := &settings.Server{ BaseURL: getParam(flags, "baseurl"), - Port: getParam(flags, "port"), Log: getParam(flags, "log"), TLSKey: getParam(flags, "key"), TLSCert: getParam(flags, "cert"), - Address: getParam(flags, "address"), Root: getParam(flags, "root"), } err = d.store.Settings.SaveServer(ser) @@ -408,7 +294,7 @@ func initConfig() { if cfgFile == "" { v.AddConfigPath(".") v.AddConfigPath("/etc/filebrowser/") - v.SetConfigName(".filebrowser") + v.SetConfigName("filebrowser") } else { v.SetConfigFile(cfgFile) } diff --git a/backend/filebrowser.yml b/backend/filebrowser.yml index efd76980..ba1f1d57 100644 --- a/backend/filebrowser.yml +++ b/backend/filebrowser.yml @@ -1,26 +1,27 @@ server: - port: 8080 + port: 8050 baseURL: /files address: '' log: stdout database: ./database.db root: /srv +general: disable-thumbnails: false disable-preview-resize: false disable-exec: false disable-type-detection-by-header: false auth: header: '' - method: '' + method: 'noauth' command: '' signup: false shell: '' -branding: +frontend: name: '' color: '' files: '' - disableExternal: '' - disableUsedPercentage: '' + disableExternal: false + disableUsedPercentage: false permissions: Admin: false Execute: true @@ -31,5 +32,4 @@ permissions: Share: true Download: true commands: -shell: rules: diff --git a/backend/go.mod b/backend/go.mod index 8ad814af..f2ab4898 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -7,6 +7,7 @@ require ( github.com/disintegration/imaging v1.6.2 github.com/dsoprea/go-exif/v3 v3.0.1 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/gorilla/mux v1.8.0 github.com/gorilla/websocket v1.5.0 @@ -35,6 +36,7 @@ require ( github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect + github.com/fatih/color v1.13.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect @@ -45,6 +47,8 @@ require ( github.com/klauspost/compress v1.11.4 // indirect github.com/klauspost/pgzip v1.2.5 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + 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/pierrec/lz4/v4 v4.1.2 // indirect @@ -58,6 +62,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // 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 gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 2c3368f4..ebb50138 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -86,6 +86,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= @@ -101,6 +103,11 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54= +github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= @@ -198,6 +205,7 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= @@ -205,6 +213,12 @@ github.com/maruel/natural v1.1.0 h1:2z1NgP/Vae+gYrtC0VuvrTJ6U35OuyUqDdfluLqMWuQ= github.com/maruel/natural v1.1.0/go.mod h1:eFVhYCcUOfZFxXoDZam8Ktya72wa79fNC3lc/leA0DQ= github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM= github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -403,6 +417,7 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -427,6 +442,8 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -507,6 +524,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= +golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= diff --git a/backend/http/auth.go b/backend/http/auth.go index e5cb2a7e..a47baec5 100644 --- a/backend/http/auth.go +++ b/backend/http/auth.go @@ -102,7 +102,7 @@ func withAdmin(fn handleFunc) handleFunc { } var loginHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { - auther, err := d.store.Auth.Get(d.settings.AuthMethod) + auther, err := d.store.Auth.Get(d.settings.Auth.Method) if err != nil { return http.StatusInternalServerError, err } diff --git a/backend/http/settings.go b/backend/http/settings.go index c412148b..ee2ab9e1 100644 --- a/backend/http/settings.go +++ b/backend/http/settings.go @@ -14,7 +14,7 @@ type settingsData struct { UserHomeBasePath string `json:"userHomeBasePath"` Defaults settings.UserDefaults `json:"defaults"` Rules []rules.Rule `json:"rules"` - Branding settings.Branding `json:"branding"` + Frontend settings.Frontend `json:"frontend"` Shell []string `json:"shell"` Commands map[string][]string `json:"commands"` } @@ -26,7 +26,7 @@ var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, UserHomeBasePath: d.settings.UserHomeBasePath, Defaults: d.settings.Defaults, Rules: d.settings.Rules, - Branding: d.settings.Branding, + Frontend: d.settings.Frontend, Shell: d.settings.Shell, Commands: d.settings.Commands, } @@ -46,7 +46,7 @@ var settingsPutHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d.settings.UserHomeBasePath = req.UserHomeBasePath d.settings.Defaults = req.Defaults d.settings.Rules = req.Rules - d.settings.Branding = req.Branding + d.settings.Frontend = req.Frontend d.settings.Shell = req.Shell d.settings.Commands = req.Commands diff --git a/backend/http/static.go b/backend/http/static.go index 500bef8b..8b7ac8c8 100644 --- a/backend/http/static.go +++ b/backend/http/static.go @@ -21,33 +21,33 @@ import ( func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys fs.FS, file, contentType string) (int, error) { w.Header().Set("Content-Type", contentType) - auther, err := d.store.Auth.Get(d.settings.AuthMethod) + auther, err := d.store.Auth.Get(d.settings.Auth.Method) if err != nil { return http.StatusInternalServerError, err } data := map[string]interface{}{ - "Name": d.settings.Branding.Name, - "DisableExternal": d.settings.Branding.DisableExternal, - "DisableUsedPercentage": d.settings.Branding.DisableUsedPercentage, - "Color": d.settings.Branding.Color, + "Name": d.settings.Frontend.Name, + "DisableExternal": d.settings.Frontend.DisableExternal, + "DisableUsedPercentage": d.settings.Frontend.DisableUsedPercentage, + "Color": d.settings.Frontend.Color, "BaseURL": d.server.BaseURL, "Version": version.Version, "StaticURL": path.Join(d.server.BaseURL, "/static"), "Signup": d.settings.Signup, - "NoAuth": d.settings.AuthMethod == auth.MethodNoAuth, - "AuthMethod": d.settings.AuthMethod, + "NoAuth": d.settings.Auth.Method == auth.MethodNoAuth, + "AuthMethod": d.settings.Auth.Method, "LoginPage": auther.LoginPage(), "CSS": false, "ReCaptcha": false, - "Theme": d.settings.Branding.Theme, + "Theme": d.settings.Frontend.Theme, "EnableThumbs": d.server.EnableThumbnails, "ResizePreview": d.server.ResizePreview, "EnableExec": d.server.EnableExec, } - if d.settings.Branding.Files != "" { - fPath := filepath.Join(d.settings.Branding.Files, "custom.css") + if d.settings.Frontend.Files != "" { + fPath := filepath.Join(d.settings.Frontend.Files, "custom.css") _, err := os.Stat(fPath) //nolint:govet if err != nil && !os.IsNotExist(err) { @@ -59,8 +59,8 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys } } - if d.settings.AuthMethod == auth.MethodJSONAuth { - raw, err := d.store.Auth.Get(d.settings.AuthMethod) //nolint:govet + if d.settings.Auth.Method == auth.MethodJSONAuth { + raw, err := d.store.Auth.Get(d.settings.Auth.Method) //nolint:govet if err != nil { return http.StatusInternalServerError, err } @@ -115,15 +115,15 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs const maxAge = 86400 // 1 day w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%v", maxAge)) - if d.settings.Branding.Files != "" { + if d.settings.Frontend.Files != "" { if strings.HasPrefix(r.URL.Path, "img/") { - fPath := filepath.Join(d.settings.Branding.Files, r.URL.Path) + fPath := filepath.Join(d.settings.Frontend.Files, r.URL.Path) if _, err := os.Stat(fPath); err == nil { http.ServeFile(w, r, fPath) return 0, nil } - } else if r.URL.Path == "custom.css" && d.settings.Branding.Files != "" { - http.ServeFile(w, r, filepath.Join(d.settings.Branding.Files, "custom.css")) + } else if r.URL.Path == "custom.css" && d.settings.Frontend.Files != "" { + http.ServeFile(w, r, filepath.Join(d.settings.Frontend.Files, "custom.css")) return 0, nil } } diff --git a/backend/settings/config.go b/backend/settings/config.go new file mode 100644 index 00000000..4f093c05 --- /dev/null +++ b/backend/settings/config.go @@ -0,0 +1,50 @@ +package settings + +import ( + "io/ioutil" + "log" + "os" + + "github.com/goccy/go-yaml" +) + +var GlobalConfiguration Settings + +func Initialize() { + // Open and read the YAML file + yamlFile, err := os.Open("filebrowser.yml") + if err != nil { + log.Fatalf("Error opening YAML file: %v", err) + } + defer yamlFile.Close() + + yamlData, err := ioutil.ReadAll(yamlFile) + 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. +} + +func setDefaults() { + GlobalConfiguration = Settings{ + Signup: true, + Server: Server{ + IndexingInterval: 5, + Port: 8080, + NumImageProcessors: 1, + BaseURL: "/files", + }, + Auth: Auth{ + Recaptcha: Recaptcha{ + Host: "", + }, + }, + } +} \ No newline at end of file diff --git a/backend/settings/settings.go b/backend/settings/settings.go index dde86d73..6b5d0dd8 100644 --- a/backend/settings/settings.go +++ b/backend/settings/settings.go @@ -35,3 +35,7 @@ func GenerateKey() ([]byte, error) { return b, nil } + +func GetSettingsConfig(nameType string,Value string) string { + return nameType + Value +} \ No newline at end of file diff --git a/backend/settings/structs.go b/backend/settings/structs.go index 5669684a..a4317ba4 100644 --- a/backend/settings/structs.go +++ b/backend/settings/structs.go @@ -29,21 +29,31 @@ type Settings struct { Shell []string `json:"shell"` Rules []rules.Rule `json:"rules"` Server Server `json:"server"` - AuthMethod string `json:"authMethod"` - Auth struct { - Header string `json:"header"` - Method string `json:"method"` - Command string `json:"command"` - Signup bool `json:"signup"` - Shell string `json:"shell"` - } `json:"auth"` + Auth Auth `json:"auth"` - Branding Branding `json:"branding"` + 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"` +} + +type Recaptcha struct { + Host string + Key string + Secret string +} + type Server struct { + IndexingInterval uint32 + NumImageProcessors int Socket string `json:"socket"` TLSKey string `json:"tlsKey"` TLSCert string `json:"tlsCert"` @@ -52,7 +62,7 @@ type Server struct { EnableExec bool `json:"enableExec"` TypeDetectionByHeader bool `json:"typeDetectionByHeader"` AuthHook string `json:"authHook"` - Port string `json:"port"` + Port int `json:"port"` BaseURL string `json:"baseURL"` Address string `json:"address"` Log string `json:"log"` @@ -61,7 +71,7 @@ type Server struct { EnablePreviewResize bool `json:"disable-preview-resize"` } -type Branding struct { +type Frontend struct { Name string `json:"name"` DisableExternal bool `json:"disableExternal"` DisableUsedPercentage bool `json:"disableUsedPercentage"` diff --git a/backend/storage/bolt/config.go b/backend/storage/bolt/config.go index 67f9eed9..cb4914c6 100644 --- a/backend/storage/bolt/config.go +++ b/backend/storage/bolt/config.go @@ -2,7 +2,6 @@ package bolt import ( "github.com/asdine/storm/v3" - "github.com/gtsteffaniak/filebrowser/settings" ) @@ -20,7 +19,10 @@ func (s settingsBackend) Save(set *settings.Settings) error { } func (s settingsBackend) GetServer() (*settings.Server, error) { - server := &settings.Server{} + server := &settings.Server{ + Port: 8080, + NumImageProcessors: 1, + } return server, get(s.db, "server", server) } diff --git a/backend/storage/bolt/importer/conf.go b/backend/storage/bolt/importer/conf.go index 939559c2..b40e155c 100644 --- a/backend/storage/bolt/importer/conf.go +++ b/backend/storage/bolt/importer/conf.go @@ -140,7 +140,7 @@ func importConf(db *storm.DB, path string, sto *storage.Storage) error { server := &settings.Server{ BaseURL: cfg.BaseURL, - Port: cfg.Port, + Port: 8080, Address: cfg.Address, Log: cfg.Log, } @@ -149,13 +149,13 @@ func importConf(db *storm.DB, path string, sto *storage.Storage) error { switch cfg.Auth.Method { case "proxy": auther = &auth.ProxyAuth{Header: cfg.Auth.Header} - s.AuthMethod = string(auth.MethodProxyAuth) + s.Auth.Method = string(auth.MethodProxyAuth) case "hook": auther = &auth.HookAuth{Command: cfg.Auth.Command} - s.AuthMethod = string(auth.MethodHookAuth) + s.Auth.Method = string(auth.MethodHookAuth) case "none": auther = &auth.NoAuth{} - s.AuthMethod = string(auth.MethodNoAuth) + s.Auth.Method = string(auth.MethodNoAuth) default: auther = &auth.JSONAuth{ ReCaptcha: &auth.ReCaptcha{ @@ -164,7 +164,7 @@ func importConf(db *storm.DB, path string, sto *storage.Storage) error { Secret: cfg.ReCaptcha.Secret, }, } - s.AuthMethod = string(auth.MethodJSONAuth) + s.Auth.Method = string(auth.MethodJSONAuth) } err = sto.Auth.Save(auther) diff --git a/backend/storage/bolt/importer/importer.go b/backend/storage/bolt/importer/importer.go index 1ecc70eb..36b60283 100644 --- a/backend/storage/bolt/importer/importer.go +++ b/backend/storage/bolt/importer/importer.go @@ -2,12 +2,14 @@ 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