add comments and update config; close #23

This commit is contained in:
Henrique Dias 2016-08-22 12:09:18 +01:00
parent e606af4eae
commit 1df11145a8
3 changed files with 81 additions and 101 deletions

View File

@ -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

View File

@ -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

View File

@ -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 {