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