mirror of
https://github.com/filebrowser/filebrowser.git
synced 2024-06-07 23:00:43 +00:00
add comments and update config; close #23
This commit is contained in:
parent
e606af4eae
commit
1df11145a8
145
config/config.go
145
config/config.go
@ -35,7 +35,11 @@ type Rule struct {
|
||||
// Parse parses the configuration set by the user so it can
|
||||
// be used by the middleware
|
||||
func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
var configs []Config
|
||||
var (
|
||||
configs []Config
|
||||
err error
|
||||
user *User
|
||||
)
|
||||
|
||||
appendConfig := func(cfg Config) error {
|
||||
for _, c := range configs {
|
||||
@ -47,12 +51,9 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
var cCfg *User
|
||||
var baseURL string
|
||||
|
||||
for c.Next() {
|
||||
var cfg = Config{User: &User{}}
|
||||
// Initialize the configuration with the default settings
|
||||
cfg := Config{User: &User{}}
|
||||
cfg.PathScope = "."
|
||||
cfg.Root = http.Dir(cfg.PathScope)
|
||||
cfg.BaseURL = ""
|
||||
@ -69,8 +70,8 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
Regexp: regexp.MustCompile("\\/\\..+"),
|
||||
}}
|
||||
|
||||
baseURL = ""
|
||||
cCfg = cfg.User
|
||||
// Set the first user, the global user
|
||||
user = cfg.User
|
||||
|
||||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
@ -78,37 +79,42 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
baseURL = c.Val()
|
||||
|
||||
cfg.BaseURL = c.Val()
|
||||
case "frontmatter":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
cCfg.FrontMatter = c.Val()
|
||||
if cCfg.FrontMatter != "yaml" && cCfg.FrontMatter != "json" && cCfg.FrontMatter != "toml" {
|
||||
|
||||
user.FrontMatter = c.Val()
|
||||
if user.FrontMatter != "yaml" && user.FrontMatter != "json" && user.FrontMatter != "toml" {
|
||||
return configs, c.Err("frontmatter type not supported")
|
||||
}
|
||||
case "show":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
cCfg.PathScope = c.Val()
|
||||
cCfg.PathScope = strings.TrimSuffix(cCfg.PathScope, "/")
|
||||
cCfg.Root = http.Dir(cCfg.PathScope)
|
||||
|
||||
user.PathScope = c.Val()
|
||||
user.PathScope = strings.TrimSuffix(user.PathScope, "/")
|
||||
user.Root = http.Dir(user.PathScope)
|
||||
case "styles":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
|
||||
var tplBytes []byte
|
||||
tplBytes, err = ioutil.ReadFile(c.Val())
|
||||
if err != nil {
|
||||
return configs, err
|
||||
}
|
||||
cCfg.StyleSheet = string(tplBytes)
|
||||
user.StyleSheet = string(tplBytes)
|
||||
case "allow_new":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
cCfg.AllowNew, err = strconv.ParseBool(c.Val())
|
||||
|
||||
user.AllowNew, err = strconv.ParseBool(c.Val())
|
||||
if err != nil {
|
||||
return configs, err
|
||||
}
|
||||
@ -116,7 +122,8 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
cCfg.AllowEdit, err = strconv.ParseBool(c.Val())
|
||||
|
||||
user.AllowEdit, err = strconv.ParseBool(c.Val())
|
||||
if err != nil {
|
||||
return configs, err
|
||||
}
|
||||
@ -124,7 +131,8 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
cCfg.AllowCommands, err = strconv.ParseBool(c.Val())
|
||||
|
||||
user.AllowCommands, err = strconv.ParseBool(c.Val())
|
||||
if err != nil {
|
||||
return configs, err
|
||||
}
|
||||
@ -133,7 +141,7 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
|
||||
cCfg.Commands = append(cCfg.Commands, c.Val())
|
||||
user.Commands = append(user.Commands, c.Val())
|
||||
case "block_command":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
@ -141,76 +149,42 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
|
||||
index := 0
|
||||
|
||||
for i, val := range cCfg.Commands {
|
||||
for i, val := range user.Commands {
|
||||
if val == c.Val() {
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
cCfg.Commands = append(cCfg.Commands[:index], cCfg.Commands[index+1:]...)
|
||||
case "allow":
|
||||
user.Commands = append(user.Commands[:index], user.Commands[index+1:]...)
|
||||
case "allow", "allow_r", "block", "block_r":
|
||||
ruleType := c.Val()
|
||||
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
|
||||
if c.Val() == "dotfiles" {
|
||||
cCfg.Rules = append(cCfg.Rules, &Rule{
|
||||
Regex: true,
|
||||
Allow: true,
|
||||
Regexp: regexp.MustCompile("\\/\\..+"),
|
||||
})
|
||||
if c.Val() == "dotfiles" && !strings.HasSuffix(ruleType, "_r") {
|
||||
ruleType += "_r"
|
||||
}
|
||||
|
||||
rule := &Rule{
|
||||
Allow: ruleType == "allow" || ruleType == "allow_r",
|
||||
Regex: ruleType == "allow_r" || ruleType == "block_r",
|
||||
}
|
||||
|
||||
if rule.Regex && c.Val() == "dotfiles" {
|
||||
rule.Regexp = regexp.MustCompile("\\/\\..+")
|
||||
} else if rule.Regex {
|
||||
rule.Regexp = regexp.MustCompile(c.Val())
|
||||
} else {
|
||||
cCfg.Rules = append(cCfg.Rules, &Rule{
|
||||
Regex: false,
|
||||
Allow: true,
|
||||
Path: c.Val(),
|
||||
Regexp: nil,
|
||||
})
|
||||
}
|
||||
case "allow_r":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
rule.Path = c.Val()
|
||||
}
|
||||
|
||||
cCfg.Rules = append(cCfg.Rules, &Rule{
|
||||
Regex: true,
|
||||
Allow: true,
|
||||
Path: "",
|
||||
Regexp: regexp.MustCompile(c.Val()),
|
||||
})
|
||||
case "block":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
|
||||
if c.Val() == "dotfiles" {
|
||||
cCfg.Rules = append(cCfg.Rules, &Rule{
|
||||
Regex: true,
|
||||
Allow: false,
|
||||
Regexp: regexp.MustCompile("\\/\\..+"),
|
||||
})
|
||||
} else {
|
||||
cCfg.Rules = append(cCfg.Rules, &Rule{
|
||||
Regex: false,
|
||||
Allow: false,
|
||||
Path: c.Val(),
|
||||
Regexp: nil,
|
||||
})
|
||||
}
|
||||
case "block_r":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
}
|
||||
|
||||
cCfg.Rules = append(cCfg.Rules, &Rule{
|
||||
Regex: true,
|
||||
Allow: false,
|
||||
Path: "",
|
||||
Regexp: regexp.MustCompile(c.Val()),
|
||||
})
|
||||
user.Rules = append(user.Rules, rule)
|
||||
// NEW USER BLOCK?
|
||||
default:
|
||||
val := c.Val()
|
||||
|
||||
// Checks if it's a new user
|
||||
if !strings.HasSuffix(val, ":") {
|
||||
fmt.Println("Unknown option " + val)
|
||||
@ -221,21 +195,19 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
cfg.Users[val] = &User{}
|
||||
|
||||
// Initialize the new user
|
||||
cCfg = cfg.Users[val]
|
||||
cCfg.AllowCommands = cfg.AllowCommands
|
||||
cCfg.AllowEdit = cfg.AllowEdit
|
||||
cCfg.AllowNew = cfg.AllowEdit
|
||||
cCfg.Commands = cfg.Commands
|
||||
cCfg.FrontMatter = cfg.FrontMatter
|
||||
cCfg.PathScope = cfg.PathScope
|
||||
cCfg.Root = cfg.Root
|
||||
cCfg.Rules = cfg.Rules
|
||||
cCfg.StyleSheet = cfg.StyleSheet
|
||||
user = cfg.Users[val]
|
||||
user.AllowCommands = cfg.AllowCommands
|
||||
user.AllowEdit = cfg.AllowEdit
|
||||
user.AllowNew = cfg.AllowEdit
|
||||
user.Commands = cfg.Commands
|
||||
user.FrontMatter = cfg.FrontMatter
|
||||
user.PathScope = cfg.PathScope
|
||||
user.Root = cfg.Root
|
||||
user.Rules = cfg.Rules
|
||||
user.StyleSheet = cfg.StyleSheet
|
||||
}
|
||||
}
|
||||
|
||||
// Set global base url
|
||||
cfg.BaseURL = baseURL
|
||||
cfg.BaseURL = strings.TrimPrefix(cfg.BaseURL, "/")
|
||||
cfg.BaseURL = strings.TrimSuffix(cfg.BaseURL, "/")
|
||||
cfg.BaseURL = "/" + cfg.BaseURL
|
||||
@ -248,7 +220,6 @@ func Parse(c *caddy.Controller) ([]Config, error) {
|
||||
if err := appendConfig(cfg); err != nil {
|
||||
return configs, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return configs, nil
|
||||
|
@ -18,9 +18,7 @@ type User struct {
|
||||
Rules []*Rule `json:"-"` // Access rules
|
||||
}
|
||||
|
||||
// REVIEW: USE USER ROOT
|
||||
|
||||
// Allowed is
|
||||
// Allowed checks if the user has permission to access a directory/file
|
||||
func (u User) Allowed(url string) bool {
|
||||
var rule *Rule
|
||||
i := len(u.Rules) - 1
|
||||
|
@ -50,13 +50,16 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
||||
c = &f.Configs[i]
|
||||
serveAssets = httpserver.Path(r.URL.Path).Matches(c.BaseURL + assets.BaseURL)
|
||||
|
||||
// Set the current User
|
||||
// Set the current user.
|
||||
username, _, _ := r.BasicAuth()
|
||||
|
||||
if _, ok := c.Users[username]; ok {
|
||||
user = c.Users[username]
|
||||
} else {
|
||||
user = c.User
|
||||
}
|
||||
|
||||
// Checks if the user has permission to access the current directory.
|
||||
if !user.Allowed(r.URL.Path) {
|
||||
if r.Method == http.MethodGet {
|
||||
return errors.PrintHTML(w, http.StatusForbidden, e.New("You don't have permission to access this page."))
|
||||
@ -65,7 +68,10 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
||||
return http.StatusForbidden, nil
|
||||
}
|
||||
|
||||
// If this request is neither to server assets, nor to upload/create
|
||||
// a new file or directory.
|
||||
if r.Method != http.MethodPost && !serveAssets {
|
||||
// Gets the information of the directory/file
|
||||
fi, code, err = directory.GetInfo(r.URL, c, user)
|
||||
if err != nil {
|
||||
if r.Method == http.MethodGet {
|
||||
@ -74,28 +80,30 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
||||
return code, err
|
||||
}
|
||||
|
||||
// If it's a dir and the path doesn't end with a trailing slash,
|
||||
// redirect the user.
|
||||
if fi.IsDir && !strings.HasSuffix(r.URL.Path, "/") {
|
||||
http.Redirect(w, r, c.AddrPath+r.URL.Path+"/", http.StatusTemporaryRedirect)
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Secure agains CSRF attacks
|
||||
// Security measures against CSRF attacks.
|
||||
if r.Method != http.MethodGet {
|
||||
if !c.CheckToken(r) {
|
||||
return http.StatusForbidden, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Route the request depending on the HTTP Method
|
||||
// Route the request depending on the HTTP Method.
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
// Read and show directory or file
|
||||
// Read and show directory or file.
|
||||
if serveAssets {
|
||||
return assets.Serve(w, r, c)
|
||||
}
|
||||
|
||||
// Generate anti security token
|
||||
// Generate anti security token.
|
||||
c.GenerateToken()
|
||||
|
||||
if !fi.IsDir {
|
||||
@ -124,10 +132,10 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
||||
return http.StatusUnauthorized, nil
|
||||
}
|
||||
|
||||
// Update a file
|
||||
// Update a file.
|
||||
return fi.Update(w, r, c, user)
|
||||
case http.MethodPost:
|
||||
// Upload a new file
|
||||
// Upload a new file.
|
||||
if r.Header.Get("Upload") == "true" {
|
||||
if !user.AllowNew {
|
||||
return http.StatusUnauthorized, nil
|
||||
@ -135,11 +143,13 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
||||
|
||||
return upload(w, r, c)
|
||||
}
|
||||
// Search and git commands
|
||||
|
||||
// Search and git commands.
|
||||
if r.Header.Get("Search") == "true" {
|
||||
// TODO: search commands
|
||||
// TODO: search commands.
|
||||
}
|
||||
// VCS commands
|
||||
|
||||
// VCS commands.
|
||||
if r.Header.Get("Command") != "" {
|
||||
if !user.AllowCommands {
|
||||
return http.StatusUnauthorized, nil
|
||||
@ -147,7 +157,8 @@ func (f FileManager) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, err
|
||||
|
||||
return command(w, r, c, user)
|
||||
}
|
||||
// Creates a new folder
|
||||
|
||||
// Creates a new folder.
|
||||
return newDirectory(w, r, c)
|
||||
case http.MethodDelete:
|
||||
if !user.AllowEdit {
|
||||
|
Loading…
Reference in New Issue
Block a user