Merge pull request #18 from gtsteffaniak/remove-settings
Remove settings
This commit is contained in:
commit
f2811ae54d
12
CHANGELOG.md
12
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
|
||||
|
|
|
@ -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" ]
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 <nil>
|
||||
2023/08/18 17:10:41 h: 401 <nil>
|
||||
2023/08/18 17:10:41 h: 401 <nil>
|
||||
2023/08/18 17:10:41 h: 401 <nil>
|
||||
2023/08/18 17:10:41 h: 401 <nil>
|
||||
2023/08/18 17:10:41 h: 401 <nil>
|
||||
ok github.com/gtsteffaniak/filebrowser/fileutils 0.004s
|
||||
2023/09/02 19:15:20 h: 401 <nil>
|
||||
2023/09/02 19:15:20 h: 401 <nil>
|
||||
2023/09/02 19:15:20 h: 401 <nil>
|
||||
2023/09/02 19:15:20 h: 401 <nil>
|
||||
2023/09/02 19:15:20 h: 401 <nil>
|
||||
2023/09/02 19:15:20 h: 401 <nil>
|
||||
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]
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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{}),
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configExportCmd)
|
||||
}
|
||||
|
||||
var configExportCmd = &cobra.Command{
|
||||
Use: "export <path>",
|
||||
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{}),
|
||||
}
|
|
@ -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}),
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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{}),
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
},
|
||||
}
|
|
@ -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) + "\""))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
})
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/bin/sh
|
||||
## TEST file used by docker testing containers
|
||||
touch render.yml
|
||||
checkExit() {
|
||||
if [ "$?" -ne 0 ];then
|
||||
exit 1
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#!/bin/sh
|
||||
## TEST file used by docker testing containers
|
||||
touch render.yml
|
||||
checkExit() {
|
||||
if [ "$?" -ne 0 ];then
|
||||
exit 1
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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":{}
|
||||
// }
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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"`
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<p>
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="settings.branding.disableExternal"
|
||||
v-model="settings.frontend.disableExternal"
|
||||
id="branding-links"
|
||||
/>
|
||||
{{ $t("settings.disableExternalLinks") }}
|
||||
|
@ -65,7 +65,7 @@
|
|||
<p>
|
||||
<input
|
||||
type="checkbox"
|
||||
v-model="settings.branding.disableUsedPercentage"
|
||||
v-model="settings.frontend.disableUsedPercentage"
|
||||
id="branding-links"
|
||||
/>
|
||||
{{ $t("settings.disableUsedDiskPercentage") }}
|
||||
|
@ -75,7 +75,7 @@
|
|||
<label for="theme">{{ $t("settings.themes.title") }}</label>
|
||||
<themes
|
||||
class="input input--block"
|
||||
:theme.sync="settings.branding.theme"
|
||||
:theme.sync="settings.frontend.theme"
|
||||
id="theme"
|
||||
></themes>
|
||||
</p>
|
||||
|
@ -85,7 +85,7 @@
|
|||
<input
|
||||
class="input input--block"
|
||||
type="text"
|
||||
v-model="settings.branding.name"
|
||||
v-model="settings.frontend.name"
|
||||
id="branding-name"
|
||||
/>
|
||||
</p>
|
||||
|
@ -97,7 +97,7 @@
|
|||
<input
|
||||
class="input input--block"
|
||||
type="text"
|
||||
v-model="settings.branding.files"
|
||||
v-model="settings.frontend.files"
|
||||
id="branding-files"
|
||||
/>
|
||||
</p>
|
||||
|
|
Loading…
Reference in New Issue