add settings/runtime.go

This commit is contained in:
1138-4EB 2019-01-07 13:44:13 +01:00
parent 25c009a560
commit b178c6af99
12 changed files with 100 additions and 67 deletions

View File

@ -28,7 +28,7 @@ override the options.`,
authMethod, auther := getAuthentication(cmd) authMethod, auther := getAuthentication(cmd)
s := &settings.Settings{ s := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit Runtime: runtimeNonDefaults(),
Signup: mustGetBool(cmd, "signup"), Signup: mustGetBool(cmd, "signup"),
Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "), Shell: strings.Split(strings.TrimSpace(mustGetString(cmd, "shell")), " "),
AuthMethod: authMethod, AuthMethod: authMethod,

View File

@ -2,13 +2,13 @@ package cmd
import ( import (
"crypto/tls" "crypto/tls"
"fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"net" "net"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"github.com/filebrowser/filebrowser/v2/auth" "github.com/filebrowser/filebrowser/v2/auth"
@ -35,15 +35,16 @@ func init() {
pf.StringVarP(&cfgFile, "config", "c", "", "config file path") pf.StringVarP(&cfgFile, "config", "c", "", "config file path")
vaddP(pf, "database", "d", "./filebrowser.db", "path to the database") vaddP(pf, "database", "d", "./filebrowser.db", "path to the database")
vaddP(f, "address", "a", "127.0.0.1", "address to listen on") vaddP(f, "address", "a", settings.RuntimeDefaults["address"], "address to listen on")
vaddP(f, "log", "l", "stdout", "log output") vaddP(f, "log", "l", settings.RuntimeDefaults["log"], "log output")
vaddP(f, "port", "p", 8080, "port to listen on") vaddP(f, "port", "p", settings.RuntimeDefaults["port"], "port to listen on")
vaddP(f, "cert", "t", "", "tls certificate") vaddP(f, "cert", "t", settings.RuntimeDefaults["cert"], "tls certificate")
vaddP(f, "key", "k", "", "tls key") vaddP(f, "key", "k", settings.RuntimeDefaults["key"], "tls key")
vaddP(f, "root", "r", ".", "root to prepend to relative paths") vaddP(f, "root", "r", settings.RuntimeDefaults["root"], "root path to prepend to all relative paths")
vaddP(f, "baseurl", "b", "", "base url") vaddP(f, "baseurl", "b", settings.RuntimeDefaults["baseurl"], "base url")
vadd(f, "username", "admin", "username for the first user when using quick config") vadd(f, "username", "admin", "username for the first user when using quick config")
vadd(f, "password", "", "hashed password for the first user when using quick config (default \"admin\")") vadd(f, "password", "", "hashed password for the first user when using quick config (default \"admin\")")
vaddP(f, "force", "f", false, "")
if err := v.BindPFlags(f); err != nil { if err := v.BindPFlags(f); err != nil {
panic(err) panic(err)
@ -97,7 +98,7 @@ user created with the credentials from options "username" and "password".`,
log.Println(cfgFile) log.Println(cfgFile)
switch logMethod := v.GetString("log"); logMethod { switch logMethod := settings.RuntimeCfg["log"]; logMethod {
case "stdout": case "stdout":
log.SetOutput(os.Stdout) log.SetOutput(os.Stdout)
case "stderr": case "stderr":
@ -117,44 +118,40 @@ user created with the credentials from options "username" and "password".`,
quickSetup(d) quickSetup(d)
} }
// TODO: check if these fields (including baseurl) are available in the DB. proceed according to --force s, err := d.store.Settings.Get()
port := v.GetInt("port")
address := v.GetString("address")
cert := v.GetString("cert")
key := v.GetString("key")
root := v.GetString("root")
root, err := filepath.Abs(root)
checkErr(err)
settings, err := d.store.Settings.Get()
checkErr(err) checkErr(err)
// Despite Base URL and Scope being "server" type of if !v.GetBool("force") {
// variables, we persist them to the database because for k := range settings.RuntimeCfg {
// they are needed during the execution and not only if y, ok := s.Runtime[k]; ok {
// to start up the server. settings.RuntimeCfg[k] = y
settings.BaseURL = v.GetString("baseurl") }
settings.Root = root }
err = d.store.Settings.Save(settings) }
checkErr(err)
handler, err := fbhttp.NewHandler(d.store) r, err := filepath.Abs(settings.RuntimeCfg["root"])
checkErr(err) checkErr(err)
settings.RuntimeCfg["root"] = r
adr := settings.RuntimeCfg["address"] + ":" + settings.RuntimeCfg["port"]
cert := settings.RuntimeCfg["cert"]
key := settings.RuntimeCfg["key"]
var listener net.Listener var listener net.Listener
if key != "" && cert != "" { if key != "" && cert != "" {
cer, err := tls.LoadX509KeyPair(cert, key) cer, err := tls.LoadX509KeyPair(cert, key)
checkErr(err) checkErr(err)
config := &tls.Config{Certificates: []tls.Certificate{cer}} listener, err = tls.Listen("tcp", adr, &tls.Config{Certificates: []tls.Certificate{cer}})
listener, err = tls.Listen("tcp", address+":"+strconv.Itoa(port), config)
checkErr(err) checkErr(err)
} else { } else {
listener, err = net.Listen("tcp", address+":"+strconv.Itoa(port)) listener, err = net.Listen("tcp", adr)
checkErr(err) checkErr(err)
} }
handler, err := fbhttp.NewHandler(d.store)
checkErr(err)
log.Println("Listening on", listener.Addr().String()) log.Println("Listening on", listener.Addr().String())
if err := http.Serve(listener, handler); err != nil { if err := http.Serve(listener, handler); err != nil {
log.Fatal(err) log.Fatal(err)
@ -162,13 +159,26 @@ user created with the credentials from options "username" and "password".`,
}, pythonConfig{allowNoDB: true}), }, pythonConfig{allowNoDB: true}),
} }
func runtimeNonDefaults() (m map[string]string) {
for k, d := range settings.RuntimeDefaults {
if x, ok := settings.RuntimeCfg[k]; ok && (x != d) {
log.Println(fmt.Sprintf("Non-default value for key '%s': %s [default: %s]", k, x, d))
m[k] = x
}
}
if settings.RuntimeCfg["key"] == "" {
log.Println("Generate random 256 bit key")
m["key"] = string(generateRandomBytes(64)) // 256 bit
}
return
}
func quickSetup(d pythonData) { func quickSetup(d pythonData) {
// TODO: save also port, address, cert, key, scope; if their values differ from defaults log.Println("Executing quick setup...")
set := &settings.Settings{ set := &settings.Settings{
Key: generateRandomBytes(64), // 256 bit Runtime: runtimeNonDefaults(),
BaseURL: v.GetString("baseurl"),
Signup: false, Signup: false,
AuthMethod: auth.MethodJSONAuth, AuthMethod: auth.MethodJSONAuth,
Defaults: settings.UserDefaults{ Defaults: settings.UserDefaults{
@ -216,6 +226,8 @@ func quickSetup(d pythonData) {
err = d.store.Users.Save(user) err = d.store.Users.Save(user)
checkErr(err) checkErr(err)
log.Println("Quick setup finished")
} }
func initConfig() { func initConfig() {
@ -239,6 +251,11 @@ func initConfig() {
panic(err) panic(err)
} }
cfgFile = "No config file used" cfgFile = "No config file used"
} else {
cfgFile = "Using config file: " + v.ConfigFileUsed()
}
for k := range settings.RuntimeDefaults {
settings.RuntimeCfg[k] = v.GetString(k)
} }
cfgFile = "Using config file: " + v.ConfigFileUsed()
} }

View File

@ -1,9 +1,9 @@
package cmd package cmd
import ( import (
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage/bolt/importer" "github.com/filebrowser/filebrowser/v2/storage/bolt/importer"
"github.com/spf13/cobra" "github.com/spf13/cobra"
v "github.com/spf13/viper"
) )
func init() { func init() {
@ -26,7 +26,7 @@ this version.`,
oldDB := mustGetString(cmd, "old.database") oldDB := mustGetString(cmd, "old.database")
oldConf := mustGetString(cmd, "old.config") oldConf := mustGetString(cmd, "old.config")
err := importer.Import(oldDB, oldConf, v.GetString("database")) err := importer.Import(oldDB, oldConf, settings.RuntimeCfg["database"])
checkErr(err) checkErr(err)
}, },
} }

View File

@ -7,9 +7,10 @@ import (
"strings" "strings"
"time" "time"
"github.com/dgrijalva/jwt-go" jwt "github.com/dgrijalva/jwt-go"
"github.com/dgrijalva/jwt-go/request" "github.com/dgrijalva/jwt-go/request"
"github.com/filebrowser/filebrowser/v2/errors" "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
) )
@ -50,7 +51,7 @@ func (e extractor) ExtractToken(r *http.Request) (string, error) {
func withUser(fn handleFunc) handleFunc { func withUser(fn handleFunc) handleFunc {
return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
keyFunc := func(token *jwt.Token) (interface{}, error) { keyFunc := func(token *jwt.Token) (interface{}, error) {
return d.settings.Key, nil return settings.RuntimeCfg["key"], nil
} }
var tk authToken var tk authToken
@ -67,7 +68,7 @@ func withUser(fn handleFunc) handleFunc {
w.Header().Add("X-Renew-Token", "true") w.Header().Add("X-Renew-Token", "true")
} }
d.user, err = d.store.Users.Get(d.settings.Root, tk.User.ID) d.user, err = d.store.Users.Get(settings.RuntimeCfg["root"], tk.User.ID)
if err != nil { if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
@ -169,7 +170,7 @@ func printToken(w http.ResponseWriter, r *http.Request, d *data, user *users.Use
} }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signed, err := token.SignedString(d.settings.Key) signed, err := token.SignedString(settings.RuntimeCfg["key"])
if err != nil { if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }

View File

@ -4,6 +4,7 @@ import (
"net/http" "net/http"
"github.com/filebrowser/filebrowser/v2/files" "github.com/filebrowser/filebrowser/v2/files"
"github.com/filebrowser/filebrowser/v2/settings"
) )
var withHashFile = func(fn handleFunc) handleFunc { var withHashFile = func(fn handleFunc) handleFunc {
@ -13,7 +14,7 @@ var withHashFile = func(fn handleFunc) handleFunc {
return errToStatus(err), err return errToStatus(err), err
} }
user, err := d.store.Users.Get(d.settings.Root, link.UserID) user, err := d.store.Users.Get(settings.RuntimeCfg["root"], link.UserID)
if err != nil { if err != nil {
return errToStatus(err), err return errToStatus(err), err
} }

View File

@ -9,6 +9,7 @@ import (
"time" "time"
"github.com/filebrowser/filebrowser/v2/errors" "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/share" "github.com/filebrowser/filebrowser/v2/share"
) )
@ -56,7 +57,7 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
var err error var err error
s, err = d.store.Share.GetPermanent(r.URL.Path, d.user.ID) s, err = d.store.Share.GetPermanent(r.URL.Path, d.user.ID)
if err == nil { if err == nil {
w.Write([]byte(d.settings.BaseURL + "/share/" + s.Hash)) w.Write([]byte(settings.RuntimeCfg["baseurl"] + "/share/" + s.Hash))
return 0, nil return 0, nil
} }
} }

View File

@ -9,8 +9,9 @@ import (
"strings" "strings"
"text/template" "text/template"
"github.com/GeertJohan/go.rice" rice "github.com/GeertJohan/go.rice"
"github.com/filebrowser/filebrowser/v2/auth" "github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/storage"
"github.com/filebrowser/filebrowser/v2/version" "github.com/filebrowser/filebrowser/v2/version"
) )
@ -18,12 +19,12 @@ import (
func handleWithStaticData(w http.ResponseWriter, r *http.Request, d *data, box *rice.Box, file, contentType string) (int, error) { func handleWithStaticData(w http.ResponseWriter, r *http.Request, d *data, box *rice.Box, file, contentType string) (int, error) {
w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Type", contentType)
staticURL := strings.TrimPrefix(d.settings.BaseURL+"/static", "/") staticURL := strings.TrimPrefix(settings.RuntimeCfg["baseurl"]+"/static", "/")
data := map[string]interface{}{ data := map[string]interface{}{
"Name": d.settings.Branding.Name, "Name": d.settings.Branding.Name,
"DisableExternal": d.settings.Branding.DisableExternal, "DisableExternal": d.settings.Branding.DisableExternal,
"BaseURL": d.settings.BaseURL, "BaseURL": settings.RuntimeCfg["baseurl"],
"Version": version.Version, "Version": version.Version,
"StaticURL": staticURL, "StaticURL": staticURL,
"Signup": d.settings.Signup, "Signup": d.settings.Signup,

View File

@ -8,6 +8,7 @@ import (
"strings" "strings"
"github.com/filebrowser/filebrowser/v2/errors" "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
@ -61,7 +62,7 @@ func withSelfOrAdmin(fn handleFunc) handleFunc {
} }
var usersGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { var usersGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
users, err := d.store.Users.Gets(d.settings.Root) users, err := d.store.Users.Gets(settings.RuntimeCfg["root"])
if err != nil { if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }
@ -78,7 +79,7 @@ var usersGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *
}) })
var userGetHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { var userGetHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
u, err := d.store.Users.Get(d.settings.Root, d.raw.(uint)) u, err := d.store.Users.Get(settings.RuntimeCfg["root"], d.raw.(uint))
if err == errors.ErrNotExist { if err == errors.ErrNotExist {
return http.StatusNotFound, err return http.StatusNotFound, err
} }
@ -147,7 +148,7 @@ var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request
req.Data.Password, err = users.HashPwd(req.Data.Password) req.Data.Password, err = users.HashPwd(req.Data.Password)
} else { } else {
var suser *users.User var suser *users.User
suser, err = d.store.Users.Get(d.settings.Root, d.raw.(uint)) suser, err = d.store.Users.Get(settings.RuntimeCfg["root"], d.raw.(uint))
req.Data.Password = suser.Password req.Data.Password = suser.Password
} }

15
settings/runtime.go Normal file
View File

@ -0,0 +1,15 @@
package settings
// RuntimeDefaults defines default values for runtime parameters
var RuntimeDefaults = map[string]string{
"root": ".",
"baseurl": "",
"address": "127.0.0.1",
"port": "8080",
"cert": "",
"key": "",
"log": "stdout",
}
// RuntimeCfg contains parameters to be used at runtime
var RuntimeCfg = map[string]string{}

View File

@ -7,9 +7,7 @@ type AuthMethod string
// Settings contain the main settings of the application. // Settings contain the main settings of the application.
type Settings struct { type Settings struct {
Key []byte `json:"key"` Runtime map[string]string `json:"runtime"`
BaseURL string `json:"baseURL"`
Root string `json:"root"`
Signup bool `json:"signup"` Signup bool `json:"signup"`
Defaults UserDefaults `json:"defaults"` Defaults UserDefaults `json:"defaults"`
AuthMethod AuthMethod `json:"authMethod"` AuthMethod AuthMethod `json:"authMethod"`

View File

@ -1,9 +1,6 @@
package settings package settings
import ( import (
"strings"
"github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/rules" "github.com/filebrowser/filebrowser/v2/rules"
"github.com/filebrowser/filebrowser/v2/users" "github.com/filebrowser/filebrowser/v2/users"
) )
@ -39,12 +36,13 @@ var defaultEvents = []string{
// Save saves the settings for the current instance. // Save saves the settings for the current instance.
func (s *Storage) Save(set *Settings) error { func (s *Storage) Save(set *Settings) error {
set.BaseURL = strings.TrimSuffix(set.BaseURL, "/") /*
set.BaseURL = strings.TrimSuffix(set.BaseURL, "/")
if len(set.Key) == 0 {
return errors.ErrEmptyKey
}
if len(set.Key) == 0 {
return errors.ErrEmptyKey
}
*/
if set.Defaults.Locale == "" { if set.Defaults.Locale == "" {
set.Defaults.Locale = "en" set.Defaults.Locale = "en"
} }

View File

@ -13,8 +13,8 @@ import (
"github.com/asdine/storm" "github.com/asdine/storm"
"github.com/filebrowser/filebrowser/v2/settings" "github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage" "github.com/filebrowser/filebrowser/v2/storage"
"github.com/pelletier/go-toml" toml "github.com/pelletier/go-toml"
"gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
type oldDefs struct { type oldDefs struct {
@ -109,9 +109,9 @@ func importConf(db *storm.DB, path string, sto *storage.Storage) error {
} }
s := &settings.Settings{ s := &settings.Settings{
Key: key, //Key: key,
BaseURL: cfg.BaseURL, //BaseURL: cfg.BaseURL,
Signup: false, Signup: false,
Defaults: settings.UserDefaults{ Defaults: settings.UserDefaults{
Scope: cfg.Defaults.Scope, Scope: cfg.Defaults.Scope,
Commands: cfg.Defaults.Commands, Commands: cfg.Defaults.Commands,