From 68bfbe5103b48e48197ef4c2af5556ae2d2501ed Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 4 Feb 2018 00:38:07 +0100 Subject: [PATCH] feat: readd caddy to this repo Former-commit-id: cf48e35cd8c5ceff57d1353c75ffacd1de96e9ad [formerly d62bc138c736881547184977110cd622f2d31847] [formerly 4270b9fb5c907097ce6babffcedafccb5a8b6356 [formerly 385cfba0ff1fb7e70008ee8ddc94d10ef7aeda74]] Former-commit-id: 04e6142a81d677781664c9a79e960465fadd3eb4 [formerly 2152b2410fb078914c788bf7f15ca8028af54c58] Former-commit-id: e88a3fce1b9d16421ce9c1aa9c63c90705878bd2 --- caddy/filemanager/filemanager.go | 52 ++++++ caddy/hugo/hugo.go | 52 ++++++ caddy/jekyll/jekyll.go | 52 ++++++ caddy/parser/parser.go | 295 +++++++++++++++++++++++++++++++ 4 files changed, 451 insertions(+) create mode 100644 caddy/filemanager/filemanager.go create mode 100644 caddy/hugo/hugo.go create mode 100644 caddy/jekyll/jekyll.go create mode 100644 caddy/parser/parser.go diff --git a/caddy/filemanager/filemanager.go b/caddy/filemanager/filemanager.go new file mode 100644 index 00000000..055fdc13 --- /dev/null +++ b/caddy/filemanager/filemanager.go @@ -0,0 +1,52 @@ +package filemanager + +import ( + "net/http" + + "github.com/filebrowser/filebrowser" + "github.com/filebrowser/filebrowser/caddy/parser" + h "github.com/filebrowser/filebrowser/http" + "github.com/mholt/caddy" + "github.com/mholt/caddy/caddyhttp/httpserver" +) + +func init() { + caddy.RegisterPlugin("filemanager", caddy.Plugin{ + ServerType: "http", + Action: setup, + }) +} + +type plugin struct { + Next httpserver.Handler + Configs []*filebrowser.FileBrowser +} + +// ServeHTTP determines if the request is for this plugin, and if all prerequisites are met. +func (f plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { + for i := range f.Configs { + // Checks if this Path should be handled by File Manager. + if !httpserver.Path(r.URL.Path).Matches(f.Configs[i].BaseURL) { + continue + } + + h.Handler(f.Configs[i]).ServeHTTP(w, r) + return 0, nil + } + + return f.Next.ServeHTTP(w, r) +} + +// setup configures a new FileManager middleware instance. +func setup(c *caddy.Controller) error { + configs, err := parser.Parse(c, "") + if err != nil { + return err + } + + httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler { + return plugin{Configs: configs, Next: next} + }) + + return nil +} diff --git a/caddy/hugo/hugo.go b/caddy/hugo/hugo.go new file mode 100644 index 00000000..97c55368 --- /dev/null +++ b/caddy/hugo/hugo.go @@ -0,0 +1,52 @@ +package hugo + +import ( + "net/http" + + "github.com/filebrowser/filebrowser" + "github.com/filebrowser/filebrowser/caddy/parser" + h "github.com/filebrowser/filebrowser/http" + "github.com/mholt/caddy" + "github.com/mholt/caddy/caddyhttp/httpserver" +) + +func init() { + caddy.RegisterPlugin("hugo", caddy.Plugin{ + ServerType: "http", + Action: setup, + }) +} + +type plugin struct { + Next httpserver.Handler + Configs []*filebrowser.FileBrowser +} + +// ServeHTTP determines if the request is for this plugin, and if all prerequisites are met. +func (f plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { + for i := range f.Configs { + // Checks if this Path should be handled by File Manager. + if !httpserver.Path(r.URL.Path).Matches(f.Configs[i].BaseURL) { + continue + } + + h.Handler(f.Configs[i]).ServeHTTP(w, r) + return 0, nil + } + + return f.Next.ServeHTTP(w, r) +} + +// setup configures a new FileManager middleware instance. +func setup(c *caddy.Controller) error { + configs, err := parser.Parse(c, "hugo") + if err != nil { + return err + } + + httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler { + return plugin{Configs: configs, Next: next} + }) + + return nil +} diff --git a/caddy/jekyll/jekyll.go b/caddy/jekyll/jekyll.go new file mode 100644 index 00000000..7dc838d1 --- /dev/null +++ b/caddy/jekyll/jekyll.go @@ -0,0 +1,52 @@ +package jekyll + +import ( + "net/http" + + "github.com/filebrowser/filebrowser" + "github.com/filebrowser/filebrowser/caddy/parser" + h "github.com/filebrowser/filebrowser/http" + "github.com/mholt/caddy" + "github.com/mholt/caddy/caddyhttp/httpserver" +) + +func init() { + caddy.RegisterPlugin("jekyll", caddy.Plugin{ + ServerType: "http", + Action: setup, + }) +} + +type plugin struct { + Next httpserver.Handler + Configs []*filebrowser.FileBrowser +} + +// ServeHTTP determines if the request is for this plugin, and if all prerequisites are met. +func (f plugin) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { + for i := range f.Configs { + // Checks if this Path should be handled by File Manager. + if !httpserver.Path(r.URL.Path).Matches(f.Configs[i].BaseURL) { + continue + } + + h.Handler(f.Configs[i]).ServeHTTP(w, r) + return 0, nil + } + + return f.Next.ServeHTTP(w, r) +} + +// setup configures a new FileManager middleware instance. +func setup(c *caddy.Controller) error { + configs, err := parser.Parse(c, "jekyll") + if err != nil { + return err + } + + httpserver.GetConfig(c).AddMiddleware(func(next httpserver.Handler) httpserver.Handler { + return plugin{Configs: configs, Next: next} + }) + + return nil +} diff --git a/caddy/parser/parser.go b/caddy/parser/parser.go new file mode 100644 index 00000000..4c318e86 --- /dev/null +++ b/caddy/parser/parser.go @@ -0,0 +1,295 @@ +package parser + +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/asdine/storm" + "github.com/filebrowser/filebrowser" + "github.com/filebrowser/filebrowser/bolt" + "github.com/filebrowser/filebrowser/staticgen" + "github.com/hacdias/fileutils" + "github.com/mholt/caddy" + "github.com/mholt/caddy/caddyhttp/httpserver" +) + +var databases = map[string]*storm.DB{} + +// Parse ... +func Parse(c *caddy.Controller, plugin string) ([]*filebrowser.FileBrowser, error) { + var ( + configs []*filebrowser.FileBrowser + err error + ) + + for c.Next() { + u := &filebrowser.User{ + Locale: "en", + AllowCommands: true, + AllowEdit: true, + AllowNew: true, + AllowPublish: true, + Commands: []string{"git", "svn", "hg"}, + CSS: "", + ViewMode: "mosaic", + Rules: []*filebrowser.Rule{{ + Regex: true, + Allow: false, + Regexp: &filebrowser.Regexp{Raw: "\\/\\..+"}, + }}, + } + + baseURL := "/" + scope := "." + database := "" + noAuth := false + reCaptchaKey := "" + reCaptchaSecret := "" + + if plugin != "" { + baseURL = "/admin" + } + + // Get the baseURL and scope + args := c.RemainingArgs() + + if plugin == "" { + if len(args) >= 1 { + baseURL = args[0] + } + + if len(args) > 1 { + scope = args[1] + } + } else { + if len(args) >= 1 { + scope = args[0] + } + + if len(args) > 1 { + baseURL = args[1] + } + } + + for c.NextBlock() { + switch c.Val() { + case "database": + if !c.NextArg() { + return nil, c.ArgErr() + } + + database = c.Val() + case "locale": + if !c.NextArg() { + return nil, c.ArgErr() + } + + u.Locale = c.Val() + case "allow_commands": + if !c.NextArg() { + u.AllowCommands = true + continue + } + + u.AllowCommands, err = strconv.ParseBool(c.Val()) + if err != nil { + return nil, err + } + case "allow_edit": + if !c.NextArg() { + u.AllowEdit = true + continue + } + + u.AllowEdit, err = strconv.ParseBool(c.Val()) + if err != nil { + return nil, err + } + case "allow_new": + if !c.NextArg() { + u.AllowNew = true + continue + } + + u.AllowNew, err = strconv.ParseBool(c.Val()) + if err != nil { + return nil, err + } + case "allow_publish": + if !c.NextArg() { + u.AllowPublish = true + continue + } + + u.AllowPublish, err = strconv.ParseBool(c.Val()) + if err != nil { + return nil, err + } + case "commands": + if !c.NextArg() { + return nil, c.ArgErr() + } + + u.Commands = strings.Split(c.Val(), " ") + case "css": + if !c.NextArg() { + return nil, c.ArgErr() + } + + file := c.Val() + css, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + + u.CSS = string(css) + case "view_mode": + if !c.NextArg() { + return nil, c.ArgErr() + } + + u.ViewMode = c.Val() + if u.ViewMode != filebrowser.MosaicViewMode && u.ViewMode != filebrowser.ListViewMode { + return nil, c.ArgErr() + } + case "recaptcha_key": + if !c.NextArg() { + return nil, c.ArgErr() + } + + reCaptchaKey = c.Val() + case "recaptcha_secret": + if !c.NextArg() { + return nil, c.ArgErr() + } + + reCaptchaSecret = c.Val() + case "no_auth": + if !c.NextArg() { + noAuth = true + continue + } + + noAuth, err = strconv.ParseBool(c.Val()) + if err != nil { + return nil, err + } + } + } + + caddyConf := httpserver.GetConfig(c) + + path := filepath.Join(caddy.AssetsPath(), "filemanager") + err := os.MkdirAll(path, 0700) + if err != nil { + return nil, err + } + + // if there is a database path and it is not absolute, + // it will be relative to Caddy folder. + if !filepath.IsAbs(database) && database != "" { + database = filepath.Join(path, database) + } + + // If there is no database path on the settings, + // store one in .caddy/filemanager/name.db. + if database == "" { + // The name of the database is the hashed value of a string composed + // by the host, address path and the baseurl of this File Manager + // instance. + hasher := md5.New() + hasher.Write([]byte(caddyConf.Addr.Host + caddyConf.Addr.Path + baseURL)) + sha := hex.EncodeToString(hasher.Sum(nil)) + database = filepath.Join(path, sha+".db") + + fmt.Println("[WARNING] A database is going to be created for your File Manager instance at " + database + + ". It is highly recommended that you set the 'database' option to '" + sha + ".db'\n") + } + + u.Scope = scope + u.FileSystem = fileutils.Dir(scope) + + var db *storm.DB + if stored, ok := databases[database]; ok { + db = stored + } else { + db, err = storm.Open(database) + databases[database] = db + } + + if err != nil { + return nil, err + } + + m := &filebrowser.FileBrowser{ + NoAuth: noAuth, + BaseURL: "", + PrefixURL: "", + ReCaptchaKey: reCaptchaKey, + ReCaptchaSecret: reCaptchaSecret, + DefaultUser: u, + Store: &filebrowser.Store{ + Config: bolt.ConfigStore{DB: db}, + Users: bolt.UsersStore{DB: db}, + Share: bolt.ShareStore{DB: db}, + }, + NewFS: func(scope string) filebrowser.FileSystem { + return fileutils.Dir(scope) + }, + } + + err = m.Setup() + if err != nil { + return nil, err + } + + switch plugin { + case "hugo": + // Initialize the default settings for Hugo. + hugo := &staticgen.Hugo{ + Root: scope, + Public: filepath.Join(scope, "public"), + Args: []string{}, + CleanPublic: true, + } + + // Attaches Hugo plugin to this file manager instance. + err = m.Attach(hugo) + if err != nil { + return nil, err + } + case "jekyll": + // Initialize the default settings for Jekyll. + jekyll := &staticgen.Jekyll{ + Root: scope, + Public: filepath.Join(scope, "_site"), + Args: []string{}, + CleanPublic: true, + } + + // Attaches Hugo plugin to this file manager instance. + err = m.Attach(jekyll) + if err != nil { + return nil, err + } + } + + if err != nil { + return nil, err + } + + m.NoAuth = noAuth + m.SetBaseURL(baseURL) + m.SetPrefixURL(strings.TrimSuffix(caddyConf.Addr.Path, "/")) + + configs = append(configs, m) + } + + return configs, nil +}