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
|
# v0.2.0
|
||||||
|
|
||||||
- Works with new more advanced filebrowser.json
|
- improved UI
|
||||||
- improved GUI
|
|
||||||
- more unified coehisive look
|
- more unified coehisive look
|
||||||
|
- Adjusted header bar look and icon behavior
|
||||||
- The shell is dead.
|
- The shell is dead.
|
||||||
- If you need to use the shell, exec into the docker container.
|
- If you need to use custom commands, exec into the docker container.
|
||||||
- All configuration is done via filebrowser.yml
|
- 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
|
# v0.1.4
|
||||||
- various UI fixes
|
- various UI fixes
|
||||||
|
|
|
@ -17,7 +17,7 @@ RUN apk --no-cache add \
|
||||||
VOLUME /srv
|
VOLUME /srv
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
WORKDIR /
|
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=base /app/filebrowser /filebrowser
|
||||||
COPY --from=nbuild /app/dist/ /frontend/dist/
|
COPY --from=nbuild /app/dist/ /frontend/dist/
|
||||||
ENTRYPOINT [ "./filebrowser" ]
|
ENTRYPOINT [ "./filebrowser" ]
|
|
@ -3,14 +3,13 @@ package auth
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gtsteffaniak/filebrowser/settings"
|
|
||||||
"github.com/gtsteffaniak/filebrowser/users"
|
"github.com/gtsteffaniak/filebrowser/users"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Auther is the authentication interface.
|
// Auther is the authentication interface.
|
||||||
type Auther interface {
|
type Auther interface {
|
||||||
// Auth is called to authenticate a request.
|
// 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 indicates if this auther needs a login page.
|
||||||
LoginPage() bool
|
LoginPage() bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ type HookAuth struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auth authenticates the user via a json in content body.
|
// 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
|
var cred hookCred
|
||||||
|
|
||||||
if r.Body == nil {
|
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.Users = usr
|
||||||
a.Settings = stg
|
a.Settings = &settings.GlobalConfiguration
|
||||||
a.Server = srv
|
a.Server = &settings.GlobalConfiguration.Server
|
||||||
a.Cred = cred
|
a.Cred = cred
|
||||||
|
|
||||||
action, err := a.RunCommand()
|
action, err := a.RunCommand()
|
||||||
|
@ -150,19 +150,18 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create user with the provided credentials
|
// create user with the provided credentials
|
||||||
d := &users.User{
|
d := &users.User{
|
||||||
Username: a.Cred.Username,
|
Username: a.Cred.Username,
|
||||||
Password: pass,
|
Password: pass,
|
||||||
Scope: a.Settings.Defaults.Scope,
|
Scope: a.Settings.UserDefaults.Scope,
|
||||||
Locale: a.Settings.Defaults.Locale,
|
Locale: a.Settings.UserDefaults.Locale,
|
||||||
ViewMode: a.Settings.Defaults.ViewMode,
|
ViewMode: a.Settings.UserDefaults.ViewMode,
|
||||||
SingleClick: a.Settings.Defaults.SingleClick,
|
SingleClick: a.Settings.UserDefaults.SingleClick,
|
||||||
Sorting: a.Settings.Defaults.Sorting,
|
Sorting: a.Settings.UserDefaults.Sorting,
|
||||||
Perm: a.Settings.Defaults.Perm,
|
Perm: a.Settings.UserDefaults.Perm,
|
||||||
Commands: a.Settings.Defaults.Commands,
|
Commands: a.Settings.UserDefaults.Commands,
|
||||||
HideDotfiles: a.Settings.Defaults.HideDotfiles,
|
HideDotfiles: a.Settings.UserDefaults.HideDotfiles,
|
||||||
}
|
}
|
||||||
u = a.GetUser(d)
|
u = a.GetUser(d)
|
||||||
|
|
||||||
|
@ -219,7 +218,7 @@ func (a *HookAuth) GetUser(d *users.User) *users.User {
|
||||||
Password: d.Password,
|
Password: d.Password,
|
||||||
Scope: a.Fields.GetString("user.scope", d.Scope),
|
Scope: a.Fields.GetString("user.scope", d.Scope),
|
||||||
Locale: a.Fields.GetString("user.locale", d.Locale),
|
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),
|
SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick),
|
||||||
Sorting: files.Sorting{
|
Sorting: files.Sorting{
|
||||||
Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc),
|
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.
|
// 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
|
var cred jsonCred
|
||||||
|
|
||||||
if r.Body == nil {
|
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) {
|
if err != nil || !users.CheckPwd(cred.Password, u.Password) {
|
||||||
return nil, os.ErrPermission
|
return nil, os.ErrPermission
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ const MethodNoAuth = "noauth"
|
||||||
type NoAuth struct{}
|
type NoAuth struct{}
|
||||||
|
|
||||||
// Auth uses authenticates user 1.
|
// Auth uses authenticates user 1.
|
||||||
func (a NoAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
|
func (a NoAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
|
||||||
return usr.Get(srv.Root, uint(1))
|
return usr.Get(settings.GlobalConfiguration.Server.Root, uint(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoginPage tells that no auth doesn't require a login page.
|
// LoginPage tells that no auth doesn't require a login page.
|
||||||
|
|
|
@ -4,8 +4,9 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gtsteffaniak/filebrowser/errors"
|
|
||||||
"github.com/gtsteffaniak/filebrowser/settings"
|
"github.com/gtsteffaniak/filebrowser/settings"
|
||||||
|
|
||||||
|
"github.com/gtsteffaniak/filebrowser/errors"
|
||||||
"github.com/gtsteffaniak/filebrowser/users"
|
"github.com/gtsteffaniak/filebrowser/users"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,9 +19,9 @@ type ProxyAuth struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auth authenticates the user via an HTTP header.
|
// 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)
|
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 {
|
if err == errors.ErrNotExist {
|
||||||
return nil, os.ErrPermission
|
return nil, os.ErrPermission
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,42 @@
|
||||||
|
|
||||||
== Running benchmark ==
|
== Running benchmark ==
|
||||||
|
/usr/local/go/bin/go
|
||||||
? github.com/gtsteffaniak/filebrowser [no test files]
|
? github.com/gtsteffaniak/filebrowser [no test files]
|
||||||
? github.com/gtsteffaniak/filebrowser/auth [no test files]
|
? github.com/gtsteffaniak/filebrowser/auth [no test files]
|
||||||
? github.com/gtsteffaniak/filebrowser/cmd [no test files]
|
? github.com/gtsteffaniak/filebrowser/cmd [no test files]
|
||||||
PASS
|
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/errors [no test files]
|
||||||
? github.com/gtsteffaniak/filebrowser/files [no test files]
|
? github.com/gtsteffaniak/filebrowser/files [no test files]
|
||||||
PASS
|
PASS
|
||||||
ok github.com/gtsteffaniak/filebrowser/fileutils 0.212s
|
ok github.com/gtsteffaniak/filebrowser/fileutils 0.004s
|
||||||
2023/08/18 17:10:41 h: 401 <nil>
|
2023/09/02 19:15:20 h: 401 <nil>
|
||||||
2023/08/18 17:10:41 h: 401 <nil>
|
2023/09/02 19:15:20 h: 401 <nil>
|
||||||
2023/08/18 17:10:41 h: 401 <nil>
|
2023/09/02 19:15:20 h: 401 <nil>
|
||||||
2023/08/18 17:10:41 h: 401 <nil>
|
2023/09/02 19:15:20 h: 401 <nil>
|
||||||
2023/08/18 17:10:41 h: 401 <nil>
|
2023/09/02 19:15:20 h: 401 <nil>
|
||||||
2023/08/18 17:10:41 h: 401 <nil>
|
2023/09/02 19:15:20 h: 401 <nil>
|
||||||
PASS
|
PASS
|
||||||
ok github.com/gtsteffaniak/filebrowser/http 0.753s
|
ok github.com/gtsteffaniak/filebrowser/http 0.094s
|
||||||
PASS
|
PASS
|
||||||
ok github.com/gtsteffaniak/filebrowser/img 0.362s
|
ok github.com/gtsteffaniak/filebrowser/img 0.122s
|
||||||
PASS
|
PASS
|
||||||
ok github.com/gtsteffaniak/filebrowser/rules 0.182s
|
ok github.com/gtsteffaniak/filebrowser/rules 0.002s
|
||||||
PASS
|
PASS
|
||||||
ok github.com/gtsteffaniak/filebrowser/runner 0.198s
|
ok github.com/gtsteffaniak/filebrowser/runner 0.004s
|
||||||
goos: darwin
|
goos: linux
|
||||||
goarch: arm64
|
goarch: amd64
|
||||||
pkg: github.com/gtsteffaniak/filebrowser/search
|
pkg: github.com/gtsteffaniak/filebrowser/search
|
||||||
BenchmarkSearchAllIndexes-10 10 5802738 ns/op 2756774 B/op 42606 allocs/op
|
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
|
||||||
BenchmarkFillIndex-10 10 4769329 ns/op 18512 B/op 453 allocs/op
|
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
|
PASS
|
||||||
ok github.com/gtsteffaniak/filebrowser/search 0.356s
|
ok github.com/gtsteffaniak/filebrowser/search 0.109s
|
||||||
? github.com/gtsteffaniak/filebrowser/settings [no test files]
|
PASS
|
||||||
|
ok github.com/gtsteffaniak/filebrowser/settings 0.004s
|
||||||
? github.com/gtsteffaniak/filebrowser/share [no test files]
|
? github.com/gtsteffaniak/filebrowser/share [no test files]
|
||||||
? github.com/gtsteffaniak/filebrowser/storage [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 [no test files]
|
||||||
? github.com/gtsteffaniak/filebrowser/storage/bolt/importer [no test files]
|
|
||||||
PASS
|
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]
|
? 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 (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
@ -13,10 +13,6 @@ import (
|
||||||
"github.com/gtsteffaniak/filebrowser/settings"
|
"github.com/gtsteffaniak/filebrowser/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
configCmd.AddCommand(configImportCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
type settingsFile struct {
|
type settingsFile struct {
|
||||||
Settings *settings.Settings `json:"settings"`
|
Settings *settings.Settings `json:"settings"`
|
||||||
Server *settings.Server `json:"server"`
|
Server *settings.Server `json:"server"`
|
||||||
|
@ -79,7 +75,6 @@ The path must be for a json or yaml file.`,
|
||||||
err = d.store.Auth.Save(auther)
|
err = d.store.Auth.Save(auther)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
printSettings(file.Server, file.Settings, auther)
|
|
||||||
}, pythonConfig{allowNoDB: true}),
|
}, pythonConfig{allowNoDB: true}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,11 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/gtsteffaniak/filebrowser/auth"
|
||||||
|
"github.com/gtsteffaniak/filebrowser/errors"
|
||||||
"github.com/gtsteffaniak/filebrowser/settings"
|
"github.com/gtsteffaniak/filebrowser/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
configCmd.AddCommand(configInitCmd)
|
|
||||||
addConfigFlags(configInitCmd.Flags())
|
|
||||||
}
|
|
||||||
|
|
||||||
var configInitCmd = &cobra.Command{
|
var configInitCmd = &cobra.Command{
|
||||||
Use: "init",
|
Use: "init",
|
||||||
Short: "Initialize a new database",
|
Short: "Initialize a new database",
|
||||||
|
@ -23,14 +20,12 @@ to the defaults when creating new users and you don't
|
||||||
override the options.`,
|
override the options.`,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
defaults := settings.UserDefaults{}
|
auther := getAuthentication()
|
||||||
flags := cmd.Flags()
|
s := settings.GlobalConfiguration
|
||||||
getUserDefaults(flags, &defaults, true)
|
s.Key = generateKey()
|
||||||
_, auther := getAuthentication()
|
err := d.store.Settings.Save(&s)
|
||||||
ser := &settings.GlobalConfiguration.Server
|
|
||||||
err := d.store.Settings.Save(&settings.GlobalConfiguration)
|
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
err = d.store.Settings.SaveServer(ser)
|
err = d.store.Settings.SaveServer(&s.Server)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
err = d.store.Auth.Save(auther)
|
err = d.store.Auth.Save(auther)
|
||||||
checkErr(err)
|
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
|
Now add your first user via 'filebrowser users add' and then you just
|
||||||
need to call the main command to boot up the server.
|
need to call the main command to boot up the server.
|
||||||
`)
|
`)
|
||||||
printSettings(ser, &settings.GlobalConfiguration, auther)
|
|
||||||
}, pythonConfig{noDB: true}),
|
}, 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}),
|
}, 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
|
func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfacer
|
||||||
sig := <-c
|
sig := <-c
|
||||||
log.Printf("Caught signal %s: shutting down.", sig)
|
log.Printf("Caught signal %s: shutting down.", sig)
|
||||||
|
@ -204,50 +210,18 @@ func setupLog(logMethod string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||||
set := &settings.Settings{
|
settings.GlobalConfiguration.Key = generateKey()
|
||||||
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,
|
|
||||||
}
|
|
||||||
var err error
|
var err error
|
||||||
if settings.GlobalConfiguration.Auth.Method == "noauth" {
|
if settings.GlobalConfiguration.Auth.Method == "noauth" {
|
||||||
set.Auth.Method = "noauth"
|
settings.GlobalConfiguration.Auth.Method = "noauth"
|
||||||
err = d.store.Auth.Save(&auth.NoAuth{})
|
err = d.store.Auth.Save(&auth.NoAuth{})
|
||||||
} else {
|
} else {
|
||||||
set.Auth.Method = "password"
|
settings.GlobalConfiguration.Auth.Method = "password"
|
||||||
err = d.store.Auth.Save(&auth.JSONAuth{})
|
err = d.store.Auth.Save(&auth.JSONAuth{})
|
||||||
}
|
}
|
||||||
err = d.store.Settings.Save(set)
|
err = d.store.Settings.Save(&settings.GlobalConfiguration)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
err = d.store.Settings.SaveServer(&settings.GlobalConfiguration.Server)
|
||||||
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)
|
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
username := getParam(flags, "username")
|
username := getParam(flags, "username")
|
||||||
|
@ -268,7 +242,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||||
LockPassword: false,
|
LockPassword: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
set.Defaults.Apply(user)
|
settings.GlobalConfiguration.UserDefaults.Apply(user)
|
||||||
user.Perm.Admin = true
|
user.Perm.Admin = true
|
||||||
|
|
||||||
err = d.store.Users.Save(user)
|
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")
|
flags.Bool("singleClick", false, "use single clicks only")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getViewMode(flags *pflag.FlagSet) users.ViewMode {
|
func getViewMode(flags *pflag.FlagSet) string {
|
||||||
viewMode := users.ViewMode(mustGetString(flags, "viewMode"))
|
viewMode := settings.GlobalConfiguration.UserDefaults.ViewMode
|
||||||
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode {
|
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode {
|
||||||
checkErr(errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(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) {
|
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||||
s, err := d.store.Settings.Get()
|
s, err := d.store.Settings.Get()
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
getUserDefaults(cmd.Flags(), &s.Defaults, false)
|
|
||||||
|
|
||||||
password, err := users.HashPwd(args[1])
|
password, err := users.HashPwd(args[1])
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
@ -30,7 +29,7 @@ var usersAddCmd = &cobra.Command{
|
||||||
LockPassword: mustGetBool(cmd.Flags(), "lockPassword"),
|
LockPassword: mustGetBool(cmd.Flags(), "lockPassword"),
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Defaults.Apply(user)
|
s.UserDefaults.Apply(user)
|
||||||
|
|
||||||
servSettings, err := d.store.Settings.GetServer()
|
servSettings, err := d.store.Settings.GetServer()
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
|
@ -49,7 +49,6 @@ options you want to change.`,
|
||||||
Sorting: user.Sorting,
|
Sorting: user.Sorting,
|
||||||
Commands: user.Commands,
|
Commands: user.Commands,
|
||||||
}
|
}
|
||||||
getUserDefaults(flags, &defaults, false)
|
|
||||||
user.Scope = defaults.Scope
|
user.Scope = defaults.Scope
|
||||||
user.Locale = defaults.Locale
|
user.Locale = defaults.Locale
|
||||||
user.ViewMode = defaults.ViewMode
|
user.ViewMode = defaults.ViewMode
|
||||||
|
|
|
@ -85,8 +85,7 @@ func dbExists(path string) (bool, error) {
|
||||||
func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
||||||
return func(cmd *cobra.Command, args []string) {
|
return func(cmd *cobra.Command, args []string) {
|
||||||
data := pythonData{hadDB: true}
|
data := pythonData{hadDB: true}
|
||||||
|
path := settings.GlobalConfiguration.Server.Database
|
||||||
path := getParam(cmd.Flags(), "database")
|
|
||||||
exists, err := dbExists(path)
|
exists, err := dbExists(path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -100,6 +99,7 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
||||||
data.hadDB = exists
|
data.hadDB = exists
|
||||||
db, err := storm.Open(path)
|
db, err := storm.Open(path)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
data.store, err = bolt.NewStorage(db)
|
data.store, err = bolt.NewStorage(db)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
server:
|
server:
|
||||||
indexingInterval: 5
|
indexingInterval: 60
|
||||||
numImageProcessors: 2
|
numImageProcessors: 8
|
||||||
socket: ""
|
socket: ""
|
||||||
tlsKey: ""
|
tlsKey: ""
|
||||||
tlsCert: ""
|
tlsCert: ""
|
||||||
|
@ -21,12 +21,12 @@ auth:
|
||||||
header: ""
|
header: ""
|
||||||
method: noauth
|
method: noauth
|
||||||
command: ""
|
command: ""
|
||||||
signup: false
|
signup: true
|
||||||
shell: ""
|
shell: ""
|
||||||
frontend:
|
frontend:
|
||||||
name: ""
|
name: ""
|
||||||
disableExternal: false
|
disableExternal: false
|
||||||
disableUsedPercentage: false
|
disableUsedPercentage: true
|
||||||
files: ""
|
files: ""
|
||||||
theme: ""
|
theme: ""
|
||||||
color: ""
|
color: ""
|
||||||
|
@ -37,16 +37,16 @@ userDefaults:
|
||||||
singleClick: false
|
singleClick: false
|
||||||
sorting:
|
sorting:
|
||||||
by: ""
|
by: ""
|
||||||
asc: false
|
asc: true
|
||||||
perm:
|
perm:
|
||||||
admin: false
|
admin: true
|
||||||
execute: false
|
execute: true
|
||||||
create: false
|
create: true
|
||||||
rename: false
|
rename: true
|
||||||
modify: false
|
modify: true
|
||||||
delete: false
|
delete: true
|
||||||
share: false
|
share: true
|
||||||
download: false
|
download: true
|
||||||
commands: []
|
commands: []
|
||||||
hideDotfiles: false
|
hideDotfiles: true
|
||||||
dateFormat: false
|
dateFormat: false
|
|
@ -9,12 +9,11 @@ require (
|
||||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
||||||
github.com/goccy/go-yaml v1.11.0
|
github.com/goccy/go-yaml v1.11.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.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/mux v1.8.0
|
||||||
github.com/gorilla/websocket v1.5.0
|
|
||||||
github.com/maruel/natural v1.1.0
|
github.com/maruel/natural v1.1.0
|
||||||
github.com/marusama/semaphore/v2 v2.5.0
|
github.com/marusama/semaphore/v2 v2.5.0
|
||||||
github.com/mholt/archiver/v3 v3.5.1
|
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/shirou/gopsutil/v3 v3.23.7
|
||||||
github.com/spf13/afero v1.9.5
|
github.com/spf13/afero v1.9.5
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
|
@ -22,7 +21,6 @@ require (
|
||||||
github.com/spf13/viper v1.16.0
|
github.com/spf13/viper v1.16.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
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/crypto v0.12.0
|
||||||
golang.org/x/image v0.11.0
|
golang.org/x/image v0.11.0
|
||||||
golang.org/x/text v0.12.0
|
golang.org/x/text v0.12.0
|
||||||
|
@ -51,6 +49,7 @@ require (
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/nwaples/rardecode v1.1.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/pierrec/lz4/v4 v4.1.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // 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/ulikunitz/xz v0.5.9 // indirect
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 // 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/net v0.10.0 // indirect
|
||||||
golang.org/x/sys v0.11.0 // indirect
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // 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/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 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
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.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/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
|
|
@ -22,7 +22,7 @@ const (
|
||||||
type userInfo struct {
|
type userInfo struct {
|
||||||
ID uint `json:"id"`
|
ID uint `json:"id"`
|
||||||
Locale string `json:"locale"`
|
Locale string `json:"locale"`
|
||||||
ViewMode users.ViewMode `json:"viewMode"`
|
ViewMode string `json:"viewMode"`
|
||||||
SingleClick bool `json:"singleClick"`
|
SingleClick bool `json:"singleClick"`
|
||||||
Perm users.Permissions `json:"perm"`
|
Perm users.Permissions `json:"perm"`
|
||||||
Commands []string `json:"commands"`
|
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
|
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 {
|
if err == os.ErrPermission {
|
||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
|
@ -145,7 +145,7 @@ var signupHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int,
|
||||||
Username: info.Username,
|
Username: info.Username,
|
||||||
}
|
}
|
||||||
|
|
||||||
d.settings.Defaults.Apply(user)
|
d.settings.UserDefaults.Apply(user)
|
||||||
|
|
||||||
pwd, err := users.HashPwd(info.Password)
|
pwd, err := users.HashPwd(info.Password)
|
||||||
if err != nil {
|
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) {
|
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User) (int, error) {
|
||||||
|
log.Printf("%#v", user)
|
||||||
claims := &authToken{
|
claims := &authToken{
|
||||||
User: userInfo{
|
User: userInfo{
|
||||||
ID: user.ID,
|
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)
|
index, static := getStaticHandlers(store, server, assetsFs)
|
||||||
|
|
||||||
// NOTE: This fixes the issue where it would redirect if people did not put a
|
// 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
|
// trailing slash in the end. I hate this decision since this allows some awful
|
||||||
// URLs https://www.gorillatoolkit.org/pkg/mux#Router.SkipClean
|
// URLs https://www.gorillatoolkit.org/pkg/mux#Router.SkipClean
|
||||||
r = r.SkipClean(true)
|
r = r.SkipClean(true)
|
||||||
|
|
||||||
monkey := func(fn handleFunc, prefix string) http.Handler {
|
monkey := func(fn handleFunc, prefix string) http.Handler {
|
||||||
return handle(fn, prefix, store, server)
|
return handle(fn, prefix, store, server)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.HandleFunc("/health", healthHandler)
|
r.HandleFunc("/health", healthHandler)
|
||||||
r.PathPrefix("/static").Handler(static)
|
r.PathPrefix("/static").Handler(static)
|
||||||
r.NotFoundHandler = index
|
r.NotFoundHandler = index
|
||||||
|
|
||||||
api := r.PathPrefix("/api").Subrouter()
|
api := r.PathPrefix("/api").Subrouter()
|
||||||
|
|
||||||
api.Handle("/login", monkey(loginHandler, ""))
|
api.Handle("/login", monkey(loginHandler, ""))
|
||||||
api.Handle("/signup", monkey(signupHandler, ""))
|
api.Handle("/signup", monkey(signupHandler, ""))
|
||||||
api.Handle("/renew", monkey(renewHandler, ""))
|
api.Handle("/renew", monkey(renewHandler, ""))
|
||||||
|
|
||||||
users := api.PathPrefix("/users").Subrouter()
|
users := api.PathPrefix("/users").Subrouter()
|
||||||
users.Handle("", monkey(usersGetHandler, "")).Methods("GET")
|
users.Handle("", monkey(usersGetHandler, "")).Methods("GET")
|
||||||
users.Handle("", monkey(userPostHandler, "")).Methods("POST")
|
users.Handle("", monkey(userPostHandler, "")).Methods("POST")
|
||||||
users.Handle("/{id:[0-9]+}", monkey(userPutHandler, "")).Methods("PUT")
|
users.Handle("/{id:[0-9]+}", monkey(userPutHandler, "")).Methods("PUT")
|
||||||
users.Handle("/{id:[0-9]+}", monkey(userGetHandler, "")).Methods("GET")
|
users.Handle("/{id:[0-9]+}", monkey(userGetHandler, "")).Methods("GET")
|
||||||
users.Handle("/{id:[0-9]+}", monkey(userDeleteHandler, "")).Methods("DELETE")
|
users.Handle("/{id:[0-9]+}", monkey(userDeleteHandler, "")).Methods("DELETE")
|
||||||
|
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourceGetHandler, "/api/resources")).Methods("GET")
|
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(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE")
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST")
|
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(resourcePutHandler, "/api/resources")).Methods("PUT")
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH")
|
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH")
|
||||||
|
|
||||||
api.PathPrefix("/usage").Handler(monkey(diskUsage, "/api/usage")).Methods("GET")
|
api.PathPrefix("/usage").Handler(monkey(diskUsage, "/api/usage")).Methods("GET")
|
||||||
|
|
||||||
api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).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(shareGetsHandler, "/api/share")).Methods("GET")
|
||||||
api.PathPrefix("/share").Handler(monkey(sharePostHandler, "/api/share")).Methods("POST")
|
api.PathPrefix("/share").Handler(monkey(sharePostHandler, "/api/share")).Methods("POST")
|
||||||
api.PathPrefix("/share").Handler(monkey(shareDeleteHandler, "/api/share")).Methods("DELETE")
|
api.PathPrefix("/share").Handler(monkey(shareDeleteHandler, "/api/share")).Methods("DELETE")
|
||||||
|
|
||||||
api.Handle("/settings", monkey(settingsGetHandler, "")).Methods("GET")
|
api.Handle("/settings", monkey(settingsGetHandler, "")).Methods("GET")
|
||||||
api.Handle("/settings", monkey(settingsPutHandler, "")).Methods("PUT")
|
api.Handle("/settings", monkey(settingsPutHandler, "")).Methods("PUT")
|
||||||
|
|
||||||
api.PathPrefix("/raw").Handler(monkey(rawHandler, "/api/raw")).Methods("GET")
|
api.PathPrefix("/raw").Handler(monkey(rawHandler, "/api/raw")).Methods("GET")
|
||||||
api.PathPrefix("/preview/{size}/{path:.*}").
|
api.PathPrefix("/preview/{size}/{path:.*}").
|
||||||
Handler(monkey(previewHandler(imgSvc, fileCache, server.EnableThumbnails, server.ResizePreview), "/api/preview")).Methods("GET")
|
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")
|
api.PathPrefix("/search").Handler(monkey(searchHandler, "/api/search")).Methods("GET")
|
||||||
|
|
||||||
public := api.PathPrefix("/public").Subrouter()
|
public := api.PathPrefix("/public").Subrouter()
|
||||||
public.PathPrefix("/dl").Handler(monkey(publicDlHandler, "/api/public/dl/")).Methods("GET")
|
public.PathPrefix("/dl").Handler(monkey(publicDlHandler, "/api/public/dl/")).Methods("GET")
|
||||||
public.PathPrefix("/share").Handler(monkey(publicShareHandler, "/api/public/share/")).Methods("GET")
|
public.PathPrefix("/share").Handler(monkey(publicShareHandler, "/api/public/share/")).Methods("GET")
|
||||||
|
|
||||||
return stripPrefix(server.BaseURL, r), nil
|
return stripPrefix(server.BaseURL, r), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
|
||||||
Signup: d.settings.Signup,
|
Signup: d.settings.Signup,
|
||||||
CreateUserDir: d.settings.CreateUserDir,
|
CreateUserDir: d.settings.CreateUserDir,
|
||||||
UserHomeBasePath: d.settings.UserHomeBasePath,
|
UserHomeBasePath: d.settings.UserHomeBasePath,
|
||||||
Defaults: d.settings.Defaults,
|
Defaults: d.settings.UserDefaults,
|
||||||
Rules: d.settings.Rules,
|
Rules: d.settings.Rules,
|
||||||
Frontend: d.settings.Frontend,
|
Frontend: d.settings.Frontend,
|
||||||
Shell: d.settings.Shell,
|
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.Signup = req.Signup
|
||||||
d.settings.CreateUserDir = req.CreateUserDir
|
d.settings.CreateUserDir = req.CreateUserDir
|
||||||
d.settings.UserHomeBasePath = req.UserHomeBasePath
|
d.settings.UserHomeBasePath = req.UserHomeBasePath
|
||||||
d.settings.Defaults = req.Defaults
|
d.settings.UserDefaults = req.Defaults
|
||||||
d.settings.Rules = req.Rules
|
d.settings.Rules = req.Rules
|
||||||
d.settings.Frontend = req.Frontend
|
d.settings.Frontend = req.Frontend
|
||||||
d.settings.Shell = req.Shell
|
d.settings.Shell = req.Shell
|
||||||
|
|
|
@ -2,8 +2,10 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gtsteffaniak/filebrowser/cmd"
|
"github.com/gtsteffaniak/filebrowser/cmd"
|
||||||
|
"github.com/gtsteffaniak/filebrowser/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cmd.Execute()
|
settings.Initialize()
|
||||||
|
cmd.StartFilebrowser()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
## TEST file used by docker testing containers
|
## TEST file used by docker testing containers
|
||||||
touch render.yml
|
|
||||||
checkExit() {
|
checkExit() {
|
||||||
if [ "$?" -ne 0 ];then
|
if [ "$?" -ne 0 ];then
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
## TEST file used by docker testing containers
|
## TEST file used by docker testing containers
|
||||||
touch render.yml
|
|
||||||
checkExit() {
|
checkExit() {
|
||||||
if [ "$?" -ne 0 ];then
|
if [ "$?" -ne 0 ];then
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -8,18 +8,30 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var GlobalConfiguration Settings
|
var GlobalConfiguration Settings
|
||||||
|
var configYml = "filebrowser.yaml"
|
||||||
|
|
||||||
func init() {
|
func Initialize() {
|
||||||
// Open and read the YAML file
|
yamlData := loadConfigFile()
|
||||||
yamlFile, err := os.Open("filebrowser.yml")
|
GlobalConfiguration = setDefaults()
|
||||||
|
err := yaml.Unmarshal(yamlData, &GlobalConfiguration)
|
||||||
if err != nil {
|
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()
|
defer yamlFile.Close()
|
||||||
|
|
||||||
stat, err := yamlFile.Stat()
|
stat, err := yamlFile.Stat()
|
||||||
if err != nil {
|
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())
|
yamlData := make([]byte, stat.Size())
|
||||||
|
@ -27,23 +39,16 @@ func init() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error reading YAML data: %v", err)
|
log.Fatalf("Error reading YAML data: %v", err)
|
||||||
}
|
}
|
||||||
setDefaults()
|
return yamlData
|
||||||
// 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() {
|
func setDefaults() Settings {
|
||||||
GlobalConfiguration = Settings{
|
return Settings{
|
||||||
Signup: true,
|
Signup: true,
|
||||||
Server: Server{
|
Server: Server{
|
||||||
IndexingInterval: 5,
|
IndexingInterval: 5,
|
||||||
Port: 8080,
|
Port: 8080,
|
||||||
NumImageProcessors: 1,
|
NumImageProcessors: 4,
|
||||||
BaseURL: "",
|
BaseURL: "",
|
||||||
},
|
},
|
||||||
Auth: Auth{
|
Auth: Auth{
|
||||||
|
@ -52,5 +57,8 @@ func setDefaults() {
|
||||||
Host: "",
|
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
|
return errors.ErrEmptyKey
|
||||||
}
|
}
|
||||||
|
|
||||||
if set.Defaults.Locale == "" {
|
if set.UserDefaults.Locale == "" {
|
||||||
set.Defaults.Locale = "en"
|
set.UserDefaults.Locale = "en"
|
||||||
}
|
}
|
||||||
|
|
||||||
if set.Defaults.Commands == nil {
|
if set.UserDefaults.Commands == nil {
|
||||||
set.Defaults.Commands = []string{}
|
set.UserDefaults.Commands = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if set.Defaults.ViewMode == "" {
|
if set.UserDefaults.ViewMode == "" {
|
||||||
set.Defaults.ViewMode = users.MosaicViewMode
|
set.UserDefaults.ViewMode = users.MosaicViewMode
|
||||||
}
|
}
|
||||||
|
|
||||||
if set.Rules == nil {
|
if set.Rules == nil {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package settings
|
package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gtsteffaniak/filebrowser/files"
|
|
||||||
"github.com/gtsteffaniak/filebrowser/rules"
|
"github.com/gtsteffaniak/filebrowser/rules"
|
||||||
"github.com/gtsteffaniak/filebrowser/users"
|
"github.com/gtsteffaniak/filebrowser/users"
|
||||||
)
|
)
|
||||||
|
@ -24,20 +23,17 @@ type Settings struct {
|
||||||
Signup bool `json:"signup"`
|
Signup bool `json:"signup"`
|
||||||
CreateUserDir bool `json:"createUserDir"`
|
CreateUserDir bool `json:"createUserDir"`
|
||||||
UserHomeBasePath string `json:"userHomeBasePath"`
|
UserHomeBasePath string `json:"userHomeBasePath"`
|
||||||
Defaults UserDefaults `json:"defaults"`
|
|
||||||
Commands map[string][]string `json:"commands"`
|
Commands map[string][]string `json:"commands"`
|
||||||
Shell []string `json:"shell"`
|
Shell []string `json:"shell"`
|
||||||
Rules []rules.Rule `json:"rules"`
|
Rules []rules.Rule `json:"rules"`
|
||||||
Server Server `json:"server"`
|
Server Server `json:"server"`
|
||||||
Auth Auth `json:"auth"`
|
Auth Auth `json:"auth"`
|
||||||
|
|
||||||
Frontend Frontend `json:"frontend"`
|
Frontend Frontend `json:"frontend"`
|
||||||
|
|
||||||
UserDefaults UserDefaults `json:"userDefaults"`
|
UserDefaults UserDefaults `json:"userDefaults"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Auth struct {
|
type Auth struct {
|
||||||
Recaptcha Recaptcha
|
Recaptcha Recaptcha `json:"recaptcha"`
|
||||||
Header string `json:"header"`
|
Header string `json:"header"`
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Command string `json:"command"`
|
Command string `json:"command"`
|
||||||
|
@ -46,9 +42,9 @@ type Auth struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Recaptcha struct {
|
type Recaptcha struct {
|
||||||
Host string
|
Host string `json:"host"`
|
||||||
Key string
|
Key string `json:"key"`
|
||||||
Secret string
|
Secret string `json:"secret"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
@ -68,7 +64,6 @@ type Server struct {
|
||||||
Log string `json:"log"`
|
Log string `json:"log"`
|
||||||
Database string `json:"database"`
|
Database string `json:"database"`
|
||||||
Root string `json:"root"`
|
Root string `json:"root"`
|
||||||
EnablePreviewResize bool `json:"disable-preview-resize"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Frontend struct {
|
type Frontend struct {
|
||||||
|
@ -85,53 +80,23 @@ type Frontend struct {
|
||||||
type UserDefaults struct {
|
type UserDefaults struct {
|
||||||
Scope string `json:"scope"`
|
Scope string `json:"scope"`
|
||||||
Locale string `json:"locale"`
|
Locale string `json:"locale"`
|
||||||
ViewMode users.ViewMode `json:"viewMode"`
|
ViewMode string `json:"viewMode"`
|
||||||
SingleClick bool `json:"singleClick"`
|
SingleClick bool `json:"singleClick"`
|
||||||
Sorting files.Sorting `json:"sorting"`
|
Sorting struct {
|
||||||
Perm users.Permissions `json:"perm"`
|
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"`
|
Commands []string `json:"commands"`
|
||||||
HideDotfiles bool `json:"hideDotfiles"`
|
HideDotfiles bool `json:"hideDotfiles"`
|
||||||
DateFormat bool `json:"dateFormat"`
|
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
|
package bolt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/asdine/storm/v3"
|
"github.com/asdine/storm/v3"
|
||||||
|
|
||||||
"github.com/gtsteffaniak/filebrowser/errors"
|
"github.com/gtsteffaniak/filebrowser/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func get(db *storm.DB, name string, to interface{}) error {
|
func get(db *storm.DB, name string, to interface{}) error {
|
||||||
|
log.Printf("name, %v , to %#v", name, to)
|
||||||
err := db.Get("config", name, to)
|
err := db.Get("config", name, to)
|
||||||
if err == storm.ErrNotFound {
|
if err == storm.ErrNotFound {
|
||||||
return errors.ErrNotExist
|
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 {
|
func save(db *storm.DB, name string, from interface{}) error {
|
||||||
|
log.Printf("name, %v , from %#v", name, from)
|
||||||
return db.Set("config", 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"
|
"github.com/gtsteffaniak/filebrowser/rules"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ViewMode describes a view mode.
|
var (
|
||||||
type ViewMode string
|
ListViewMode = "list"
|
||||||
|
MosaicViewMode = "mosaic"
|
||||||
const (
|
|
||||||
ListViewMode ViewMode = "list"
|
|
||||||
MosaicViewMode ViewMode = "mosaic"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// User describes a user.
|
// User describes a user.
|
||||||
|
@ -27,7 +24,7 @@ type User struct {
|
||||||
Scope string `json:"scope"`
|
Scope string `json:"scope"`
|
||||||
Locale string `json:"locale"`
|
Locale string `json:"locale"`
|
||||||
LockPassword bool `json:"lockPassword"`
|
LockPassword bool `json:"lockPassword"`
|
||||||
ViewMode ViewMode `json:"viewMode"`
|
ViewMode string `json:"viewMode"`
|
||||||
SingleClick bool `json:"singleClick"`
|
SingleClick bool `json:"singleClick"`
|
||||||
Perm Permissions `json:"perm"`
|
Perm Permissions `json:"perm"`
|
||||||
Commands []string `json:"commands"`
|
Commands []string `json:"commands"`
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
<p>
|
<p>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="settings.branding.disableExternal"
|
v-model="settings.frontend.disableExternal"
|
||||||
id="branding-links"
|
id="branding-links"
|
||||||
/>
|
/>
|
||||||
{{ $t("settings.disableExternalLinks") }}
|
{{ $t("settings.disableExternalLinks") }}
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
<p>
|
<p>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
v-model="settings.branding.disableUsedPercentage"
|
v-model="settings.frontend.disableUsedPercentage"
|
||||||
id="branding-links"
|
id="branding-links"
|
||||||
/>
|
/>
|
||||||
{{ $t("settings.disableUsedDiskPercentage") }}
|
{{ $t("settings.disableUsedDiskPercentage") }}
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
<label for="theme">{{ $t("settings.themes.title") }}</label>
|
<label for="theme">{{ $t("settings.themes.title") }}</label>
|
||||||
<themes
|
<themes
|
||||||
class="input input--block"
|
class="input input--block"
|
||||||
:theme.sync="settings.branding.theme"
|
:theme.sync="settings.frontend.theme"
|
||||||
id="theme"
|
id="theme"
|
||||||
></themes>
|
></themes>
|
||||||
</p>
|
</p>
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
<input
|
<input
|
||||||
class="input input--block"
|
class="input input--block"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="settings.branding.name"
|
v-model="settings.frontend.name"
|
||||||
id="branding-name"
|
id="branding-name"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
<input
|
<input
|
||||||
class="input input--block"
|
class="input input--block"
|
||||||
type="text"
|
type="text"
|
||||||
v-model="settings.branding.files"
|
v-model="settings.frontend.files"
|
||||||
id="branding-files"
|
id="branding-files"
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
|
|
Loading…
Reference in New Issue