Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25c20aaeb2 | ||
|
|
4c665ec69c | ||
|
|
75ed779b17 | ||
|
|
6c360ffc5c | ||
|
|
f40731d3b4 | ||
|
|
afb10cc02c | ||
|
|
5d2e8864e5 | ||
|
|
d82f198b48 | ||
|
|
bbbf2bac51 | ||
|
|
d87a8ee5ed | ||
|
|
a81cc1e4ca | ||
|
|
6c5111fd6e | ||
|
|
e846c16336 | ||
|
|
dde01c6931 | ||
|
|
8b40dc9d19 | ||
|
|
63fb4c0c52 | ||
|
|
76047f4146 | ||
|
|
fc4c6ec246 | ||
|
|
f5e93825d8 | ||
|
|
73d74394c8 | ||
|
|
3469d8c6e8 | ||
|
|
be082c1075 | ||
|
|
f271b18d97 | ||
|
|
a728d0352e | ||
|
|
2096d7d048 |
4
.dockerignore
Normal file
4
.dockerignore
Normal file
@@ -0,0 +1,4 @@
|
||||
assets/
|
||||
testdata/
|
||||
caddy/
|
||||
.github/
|
||||
@@ -9,7 +9,6 @@ env:
|
||||
install:
|
||||
- go get ./...
|
||||
- go get github.com/mitchellh/gox
|
||||
- go get github.com/tcnksm/ghr
|
||||
# Install gometalinter and certain linters
|
||||
- go get github.com/alecthomas/gometalinter
|
||||
- go get github.com/client9/misspell/cmd/misspell
|
||||
@@ -20,11 +19,11 @@ install:
|
||||
script:
|
||||
- gometalinter --disable-all -E vet -E gofmt -E misspell -E ineffassign -E goimports -E deadcode --exclude="rice-box.go" --tests ./...
|
||||
- go test ./... -timeout 30s
|
||||
|
||||
before_deploy:
|
||||
- cd cmd/filemanager
|
||||
- mkdir dist
|
||||
- gox -output "dist/{{.OS}}-{{.Arch}}-{{.Dir}}"
|
||||
- ls dist/
|
||||
- ghr --username hacdias --token $GITHUB_TOKEN --replace --prerelease --debug latest dist/
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
|
||||
10
Docker.json
Normal file
10
Docker.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"port": 80,
|
||||
"address": "",
|
||||
"database": "/etc/database.db",
|
||||
"scope": "/srv",
|
||||
"allowCommands": true,
|
||||
"allowEdit": true,
|
||||
"allowNew": true,
|
||||
"commands": []
|
||||
}
|
||||
21
Dockerfile
Normal file
21
Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
||||
FROM golang:alpine
|
||||
|
||||
COPY . /go/src/github.com/hacdias/filemanager
|
||||
|
||||
WORKDIR /go/src/github.com/hacdias/filemanager
|
||||
RUN apk add --no-cache git
|
||||
RUN go get ./...
|
||||
|
||||
WORKDIR /go/src/github.com/hacdias/filemanager/cmd/filemanager
|
||||
RUN go install
|
||||
|
||||
FROM alpine:latest
|
||||
COPY --from=0 /go/bin/filemanager /usr/local/bin/filemanager
|
||||
|
||||
VOLUME /srv
|
||||
EXPOSE 80
|
||||
|
||||
COPY Docker.json /etc/config.json
|
||||
|
||||
ENTRYPOINT ["/usr/local/bin/filemanager"]
|
||||
CMD ["--config", "/etc/config.json"]
|
||||
21
README.md
21
README.md
@@ -34,7 +34,7 @@ The easiest way to get started is using this with Caddy web server. You just nee
|
||||
|
||||
## Standalone
|
||||
|
||||
You can use filemanager as a standalone executable. You just need to download it from the [releases page](https://github.com/hacdias/filemanager/releases), where you can find multiple releases. The 'latest' always corresponds to the latest commit made to the master branch so it might not be stable.
|
||||
You can use filemanager as a standalone executable. You just need to download it from the [releases page](https://github.com/hacdias/filemanager/releases), where you can find multiple releases.
|
||||
|
||||
You can either use flags or a JSON configuration file, which should have the following appearance:
|
||||
|
||||
@@ -77,6 +77,10 @@ Otherwise, you may not want to use a configuration file, which can be done using
|
||||
Default scope for new users (default ".")
|
||||
```
|
||||
|
||||
## Docker
|
||||
|
||||
(TODO)
|
||||
|
||||
# Features
|
||||
|
||||
Easy login system.
|
||||
@@ -127,18 +131,19 @@ this are keywords case:insensitive
|
||||
|
||||
# Contributing
|
||||
|
||||
If you want to contribute or want to build the code from source, you will need to have NodeJS and Go installed on your computer. You should start by doing the following:
|
||||
If you want to contribute or want to build the code from source, you will need to have the most recent version of Go and, if you want to change the static assets (JS, CSS, ...), Node.js installed on your computer. To start developing, you just need to do the following:
|
||||
|
||||
```
|
||||
go get github.com/hacdias/filemanager
|
||||
```
|
||||
1. `go get github.com/hacdias/filemanager`
|
||||
2. `cd $GOPATH/src/github.com/hacdias/filemanager`
|
||||
3. `npm install`
|
||||
4. `npm start dev` - regenerates the static assets automatically
|
||||
5. `go install gihthub.com/hacdias/filemanager/cmd/filemanager`
|
||||
6. Execute `$GOPATH/bin/filemanager`
|
||||
|
||||
Then, you should navigate to `$GOPATH/src/github.com/hacdias/filemanager` and execute `npm install`. You can start the live build of static assets with the command `npm start dev`.
|
||||
The steps 3 and 4 are only required **if you want to develop the front-end**. Otherwise, you can ignore them. Before pulling, if you made any change on assets folder, you must run the `build.sh` script on the root of this repository.
|
||||
|
||||
If you are using this as a Caddy plugin, you should use its [official instructions for plugins](https://github.com/mholt/caddy/wiki/Extending-Caddy#2-plug-in-your-plugin) and import `github.com/hacdias/filemanager/caddy/filemanager`.
|
||||
|
||||
Before pulling, and if you made any change on assets folder, you must run the `build.sh` script on the root of this repository.
|
||||
|
||||
# Donate
|
||||
|
||||
Enjoying this project? You can [donate to its creator](https://henriquedias.com/donate/). He will appreciate.
|
||||
|
||||
@@ -47,7 +47,8 @@ export default {
|
||||
ongoing: false,
|
||||
scrollable: null,
|
||||
search: [],
|
||||
commands: []
|
||||
commands: [],
|
||||
reload: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -57,12 +58,17 @@ export default {
|
||||
// If the hover was search and now it's something else
|
||||
// we should blur the input.
|
||||
if (old === 'search' && val !== 'search') {
|
||||
if (this.reload) {
|
||||
this.$store.commit('setReload', true)
|
||||
}
|
||||
|
||||
this.$refs.input.blur()
|
||||
}
|
||||
|
||||
// If we are starting to show the search box, we should
|
||||
// focus the input.
|
||||
if (val === 'search') {
|
||||
this.reload = false
|
||||
this.$refs.input.focus()
|
||||
}
|
||||
}
|
||||
@@ -129,7 +135,7 @@ export default {
|
||||
let pieces = this.value.split(' ')
|
||||
|
||||
for (let i = 0; i < this.user.commands.length; i++) {
|
||||
if (pieces[0] === this.user.commands[0]) {
|
||||
if (pieces[0] === this.user.commands[i]) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -166,9 +172,9 @@ export default {
|
||||
this.scrollable.scrollTop = this.scrollable.scrollHeight
|
||||
},
|
||||
(event) => {
|
||||
this.reload = true
|
||||
this.ongoing = false
|
||||
this.scrollable.scrollTop = this.scrollable.scrollHeight
|
||||
this.$store.commit('setReload', true)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</div>
|
||||
|
||||
<p class="credits">
|
||||
<span>Served with <a rel="noopener noreferrer" href="https://github.com/hacdias/caddy-filemanager">File Manager</a>.</span>
|
||||
<span>Served with <a rel="noopener noreferrer" href="https://github.com/hacdias/filemanager">File Manager</a>.</span>
|
||||
<span v-for="plugin in plugins" :key="plugin.name" v-html="plugin.credits"><br></span>
|
||||
<span><a @click="help">Help</a></span>
|
||||
</p>
|
||||
|
||||
@@ -163,7 +163,7 @@ function checksum (url, algo) {
|
||||
function command (url, command, onmessage, onclose) {
|
||||
let protocol = (ssl ? 'wss:' : 'ws:')
|
||||
url = removePrefix(url)
|
||||
url = `${protocol}//${window.location.hostname}${store.state.baseURL}/api/command${url}`
|
||||
url = `${protocol}//${window.location.host}${store.state.baseURL}/api/command${url}`
|
||||
|
||||
let conn = new window.WebSocket(url)
|
||||
conn.onopen = () => conn.send(command)
|
||||
@@ -174,7 +174,7 @@ function command (url, command, onmessage, onclose) {
|
||||
function search (url, search, onmessage, onclose) {
|
||||
let protocol = (ssl ? 'wss:' : 'ws:')
|
||||
url = removePrefix(url)
|
||||
url = `${protocol}//${window.location.hostname}${store.state.baseURL}/api/search${url}`
|
||||
url = `${protocol}//${window.location.host}${store.state.baseURL}/api/search${url}`
|
||||
|
||||
let conn = new window.WebSocket(url)
|
||||
conn.onopen = () => conn.send(search)
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"strings"
|
||||
|
||||
. "github.com/hacdias/filemanager"
|
||||
"github.com/hacdias/filemanager/dir"
|
||||
"github.com/hacdias/fileutils"
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
)
|
||||
@@ -136,7 +136,7 @@ func parse(c *caddy.Controller) ([]*config, error) {
|
||||
Regexp: &Regexp{Raw: "\\/\\..+"},
|
||||
}},
|
||||
CSS: "",
|
||||
FileSystem: dir.Dir(baseScope),
|
||||
FileSystem: fileutils.Dir(baseScope),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
"github.com/hacdias/filemanager"
|
||||
"github.com/hacdias/filemanager/variables"
|
||||
"github.com/hacdias/varutils"
|
||||
"github.com/robfig/cron"
|
||||
)
|
||||
|
||||
@@ -71,7 +71,6 @@ func (h hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r
|
||||
}
|
||||
|
||||
filename := filepath.Join(string(c.User.FileSystem), r.URL.Path)
|
||||
filename = strings.TrimPrefix(filename, "/")
|
||||
archetype := r.Header.Get("archetype")
|
||||
|
||||
ext := filepath.Ext(filename)
|
||||
@@ -100,7 +99,6 @@ func (h hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r
|
||||
}
|
||||
|
||||
filename := filepath.Join(string(c.User.FileSystem), r.URL.Path)
|
||||
filename = strings.TrimPrefix(filename, "/")
|
||||
|
||||
// Before save command handler.
|
||||
if err := c.FM.Runner("before_publish", filename); err != nil {
|
||||
@@ -110,7 +108,7 @@ func (h hugo) BeforeAPI(c *filemanager.RequestContext, w http.ResponseWriter, r
|
||||
// We only run undraft command if it is a file.
|
||||
if !strings.HasSuffix(filename, "/") {
|
||||
args := []string{"undraft", filename}
|
||||
if err := Run(h.Exe, args, h.Root); err != nil {
|
||||
if err := Run(h.Exe, args, h.Root); err != nil && !strings.Contains(err.Error(), "not a Draft") {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
@@ -142,7 +140,7 @@ func (h hugo) AfterAPI(c *filemanager.RequestContext, w http.ResponseWriter, r *
|
||||
}
|
||||
|
||||
func (h hugo) JavaScript() string {
|
||||
return rice.MustFindBox("./").MustString("hugo.js")
|
||||
return rice.MustFindBox("./assets/").MustString("hugo.js")
|
||||
}
|
||||
|
||||
// run runs Hugo with the define arguments.
|
||||
@@ -153,7 +151,7 @@ func (h hugo) run(force bool) {
|
||||
}
|
||||
|
||||
// Prevent running if watching is enabled
|
||||
if b, pos := variables.StringInSlice("--watch", h.Args); b && !force {
|
||||
if b, pos := varutils.StringInSlice("--watch", h.Args); b && !force {
|
||||
if len(h.Args) > pos && h.Args[pos+1] != "false" {
|
||||
return
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -12,7 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/hacdias/filemanager"
|
||||
"github.com/hacdias/filemanager/dir"
|
||||
"github.com/hacdias/fileutils"
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
)
|
||||
@@ -52,7 +52,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
|
||||
// Get the baseURL and baseScope
|
||||
args := c.RemainingArgs()
|
||||
|
||||
if len(args) == 1 {
|
||||
if len(args) >= 1 {
|
||||
directory = args[0]
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
|
||||
Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
|
||||
}},
|
||||
CSS: "",
|
||||
FileSystem: dir.Dir(directory),
|
||||
FileSystem: fileutils.Dir(directory),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/hacdias/filemanager"
|
||||
"github.com/hacdias/filemanager/dir"
|
||||
"github.com/hacdias/fileutils"
|
||||
)
|
||||
|
||||
// confFile contains the configuration file for this File Manager instance.
|
||||
@@ -65,7 +65,7 @@ func main() {
|
||||
Commands: strings.Split(strings.TrimSpace(commands), " "),
|
||||
Rules: []*filemanager.Rule{},
|
||||
CSS: "",
|
||||
FileSystem: dir.Dir(scope),
|
||||
FileSystem: fileutils.Dir(scope),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
||||
230
dir/dir.go
230
dir/dir.go
@@ -1,230 +0,0 @@
|
||||
// Package dir implements a FileSystem interface using the native
|
||||
// file system restricted to a specific directory tree. Originally from
|
||||
// https://github.com/golang/net/blob/master/webdav/file.go#L68
|
||||
package dir
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A Dir uses the native file system restricted to a specific directory tree.
|
||||
//
|
||||
// While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's
|
||||
// string value is a filename on the native file system, not a URL, so it is
|
||||
// separated by filepath.Separator, which isn't necessarily '/'.
|
||||
//
|
||||
// An empty Dir is treated as ".".
|
||||
type Dir string
|
||||
|
||||
func (d Dir) resolve(name string) string {
|
||||
// This implementation is based on Dir.Open's code in the standard net/http package.
|
||||
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
|
||||
strings.Contains(name, "\x00") {
|
||||
return ""
|
||||
}
|
||||
|
||||
dir := string(d)
|
||||
if dir == "" {
|
||||
dir = "."
|
||||
}
|
||||
|
||||
return filepath.Join(dir, filepath.FromSlash(SlashClean(name)))
|
||||
}
|
||||
|
||||
// Mkdir implements os.Mkdir in this directory context.
|
||||
func (d Dir) Mkdir(name string, perm os.FileMode) error {
|
||||
if name = d.resolve(name); name == "" {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
return os.Mkdir(name, perm)
|
||||
}
|
||||
|
||||
// OpenFile implements os.OpenFile in this directory context.
|
||||
func (d Dir) OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
if name = d.resolve(name); name == "" {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
f, err := os.OpenFile(name, flag, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// RemoveAll implements os.RemoveAll in this directory context.
|
||||
func (d Dir) RemoveAll(name string) error {
|
||||
if name = d.resolve(name); name == "" {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
if name == filepath.Clean(string(d)) {
|
||||
// Prohibit removing the virtual root directory.
|
||||
return os.ErrInvalid
|
||||
}
|
||||
return os.RemoveAll(name)
|
||||
}
|
||||
|
||||
// Rename implements os.Rename in this directory context.
|
||||
func (d Dir) Rename(oldName, newName string) error {
|
||||
if oldName = d.resolve(oldName); oldName == "" {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
if newName = d.resolve(newName); newName == "" {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
if root := filepath.Clean(string(d)); root == oldName || root == newName {
|
||||
// Prohibit renaming from or to the virtual root directory.
|
||||
return os.ErrInvalid
|
||||
}
|
||||
return os.Rename(oldName, newName)
|
||||
}
|
||||
|
||||
// Stat implements os.Stat in this directory context.
|
||||
func (d Dir) Stat(name string) (os.FileInfo, error) {
|
||||
if name = d.resolve(name); name == "" {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
return os.Stat(name)
|
||||
}
|
||||
|
||||
// Copy copies a file or directory from src to dst. If it is
|
||||
// a directory, all of the files and sub-directories will be copied.
|
||||
func (d Dir) Copy(src, dst string) error {
|
||||
if src = d.resolve(src); src == "" {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
if dst = d.resolve(dst); dst == "" {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
|
||||
if root := filepath.Clean(string(d)); root == src || root == dst {
|
||||
// Prohibit copying from or to the virtual root directory.
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
if dst == src {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
|
||||
info, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
return CopyDir(src, dst)
|
||||
}
|
||||
|
||||
return CopyFile(src, dst)
|
||||
}
|
||||
|
||||
// SlashClean is equivalent to but slightly more efficient than
|
||||
// path.Clean("/" + name).
|
||||
func SlashClean(name string) string {
|
||||
if name == "" || name[0] != '/' {
|
||||
name = "/" + name
|
||||
}
|
||||
return path.Clean(name)
|
||||
}
|
||||
|
||||
// CopyFile copies a file from source to dest and returns
|
||||
// an error if any.
|
||||
func CopyFile(source string, dest string) error {
|
||||
// Open the source file.
|
||||
src, err := os.Open(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
// Makes the directory needed to create the dst
|
||||
// file.
|
||||
err = os.MkdirAll(filepath.Dir(dest), 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the destination file.
|
||||
dst, err := os.Create(dest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dst.Close()
|
||||
|
||||
// Copy the contents of the file.
|
||||
_, err = io.Copy(dst, src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy the mode if the user can't
|
||||
// open the file.
|
||||
info, err := os.Stat(source)
|
||||
if err != nil {
|
||||
err = os.Chmod(dest, info.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyDir copies a directory from source to dest and all
|
||||
// of its sub-directories. It doesn't stop if it finds an error
|
||||
// during the copy. Returns an error if any.
|
||||
func CopyDir(source string, dest string) error {
|
||||
// Get properties of source.
|
||||
srcinfo, err := os.Stat(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the destination directory.
|
||||
err = os.MkdirAll(dest, srcinfo.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir, _ := os.Open(source)
|
||||
obs, err := dir.Readdir(-1)
|
||||
|
||||
var errs []error
|
||||
|
||||
for _, obj := range obs {
|
||||
fsource := source + "/" + obj.Name()
|
||||
fdest := dest + "/" + obj.Name()
|
||||
|
||||
if obj.IsDir() {
|
||||
// Create sub-directories, recursively.
|
||||
err = CopyDir(fsource, fdest)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
} else {
|
||||
// Perform the file copy.
|
||||
err = CopyFile(fsource, fdest)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var errString string
|
||||
for _, err := range errs {
|
||||
errString += err.Error() + "\n"
|
||||
}
|
||||
|
||||
if errString != "" {
|
||||
return errors.New(errString)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hacdias/filemanager/dir"
|
||||
"github.com/hacdias/fileutils"
|
||||
"github.com/mholt/archiver"
|
||||
)
|
||||
|
||||
@@ -45,7 +45,7 @@ func downloadHandler(c *RequestContext, w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
||||
// Clean the slashes.
|
||||
name = dir.SlashClean(name)
|
||||
name = fileutils.SlashClean(name)
|
||||
files = append(files, filepath.Join(c.FI.Path, name))
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
"github.com/asdine/storm"
|
||||
"github.com/hacdias/filemanager/dir"
|
||||
"github.com/hacdias/fileutils"
|
||||
"github.com/mholt/caddy"
|
||||
)
|
||||
|
||||
@@ -76,7 +76,7 @@ type User struct {
|
||||
Admin bool `json:"admin"`
|
||||
|
||||
// FileSystem is the virtual file system the user has access.
|
||||
FileSystem dir.Dir `json:"filesystem"`
|
||||
FileSystem fileutils.Dir `json:"filesystem"`
|
||||
|
||||
// Rules is an array of access and deny rules.
|
||||
Rules []*Rule `json:"rules"`
|
||||
@@ -136,7 +136,7 @@ var DefaultUser = User{
|
||||
Rules: []*Rule{},
|
||||
CSS: "",
|
||||
Admin: true,
|
||||
FileSystem: dir.Dir("."),
|
||||
FileSystem: fileutils.Dir("."),
|
||||
}
|
||||
|
||||
// New creates a new File Manager instance. If 'database' file already
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/hacdias/filemanager/dir"
|
||||
"github.com/hacdias/fileutils"
|
||||
)
|
||||
|
||||
type test struct {
|
||||
@@ -28,13 +28,13 @@ func newTest(t *testing.T) *test {
|
||||
scope := filepath.Join(temp, "scope")
|
||||
database := filepath.Join(temp, "database.db")
|
||||
|
||||
err = dir.CopyDir("./testdata", scope)
|
||||
err = fileutils.CopyDir("./testdata", scope)
|
||||
if err != nil {
|
||||
t.Fatalf("Error copying the test data: %v", err)
|
||||
}
|
||||
|
||||
user := DefaultUser
|
||||
user.FileSystem = dir.Dir(scope)
|
||||
user.FileSystem = fileutils.Dir(scope)
|
||||
|
||||
fm, err := New(database, user)
|
||||
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hacdias/filemanager/dir"
|
||||
"github.com/hacdias/fileutils"
|
||||
)
|
||||
|
||||
// sanitizeURL sanitizes the URL to prevent path transversal
|
||||
// using dir.SlashClean and adds the trailing slash bar.
|
||||
// using fileutils.SlashClean and adds the trailing slash bar.
|
||||
func sanitizeURL(url string) string {
|
||||
path := dir.SlashClean(url)
|
||||
path := fileutils.SlashClean(url)
|
||||
if strings.HasSuffix(url, "/") && path != "/" {
|
||||
return path + "/"
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
be97c942365e7a765698a8c0175b4eec18cb4899
|
||||
8868d0da70d74a9255e7fd2617e88a63ba160479
|
||||
@@ -1,13 +0,0 @@
|
||||
package variables
|
||||
|
||||
import "reflect"
|
||||
|
||||
// IsMap checks if some variable is a map
|
||||
func IsMap(sth interface{}) bool {
|
||||
return reflect.ValueOf(sth).Kind() == reflect.Map
|
||||
}
|
||||
|
||||
// IsSlice checks if some variable is a slice
|
||||
func IsSlice(sth interface{}) bool {
|
||||
return reflect.ValueOf(sth).Kind() == reflect.Slice
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package variables
|
||||
|
||||
import "testing"
|
||||
|
||||
type interfaceToBool struct {
|
||||
Value interface{}
|
||||
Result bool
|
||||
}
|
||||
|
||||
var testIsMap = []*interfaceToBool{
|
||||
{"teste", false},
|
||||
{453478, false},
|
||||
{-984512, false},
|
||||
{true, false},
|
||||
{map[string]bool{}, true},
|
||||
{map[int]bool{}, true},
|
||||
{map[interface{}]bool{}, true},
|
||||
{[]string{}, false},
|
||||
}
|
||||
|
||||
func TestIsMap(t *testing.T) {
|
||||
for _, test := range testIsMap {
|
||||
if IsMap(test.Value) != test.Result {
|
||||
t.Errorf("Incorrect value on IsMap for %v; want: %v; got: %v", test.Value, test.Result, !test.Result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var testIsSlice = []*interfaceToBool{
|
||||
{"teste", false},
|
||||
{453478, false},
|
||||
{-984512, false},
|
||||
{true, false},
|
||||
{map[string]bool{}, false},
|
||||
{map[int]bool{}, false},
|
||||
{map[interface{}]bool{}, false},
|
||||
{[]string{}, true},
|
||||
{[]int{}, true},
|
||||
{[]bool{}, true},
|
||||
{[]interface{}{}, true},
|
||||
}
|
||||
|
||||
func TestIsSlice(t *testing.T) {
|
||||
for _, test := range testIsSlice {
|
||||
if IsSlice(test.Value) != test.Result {
|
||||
t.Errorf("Incorrect value on IsSlice for %v; want: %v; got: %v", test.Value, test.Result, !test.Result)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package variables
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Dict allows to send more than one variable into a template.
|
||||
func Dict(values ...interface{}) (map[string]interface{}, error) {
|
||||
if len(values)%2 != 0 {
|
||||
return nil, errors.New("invalid dict call")
|
||||
}
|
||||
dict := make(map[string]interface{}, len(values)/2)
|
||||
for i := 0; i < len(values); i += 2 {
|
||||
key, ok := values[i].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("dict keys must be strings")
|
||||
}
|
||||
dict[key] = values[i+1]
|
||||
}
|
||||
|
||||
return dict, nil
|
||||
}
|
||||
|
||||
// FieldInStruct checks if variable is defined in a struct.
|
||||
func FieldInStruct(data interface{}, field string) bool {
|
||||
t := reflect.Indirect(reflect.ValueOf(data)).Type()
|
||||
|
||||
if t.Kind() != reflect.Struct {
|
||||
log.Print("Non-struct type not allowed.")
|
||||
return false
|
||||
}
|
||||
|
||||
_, b := t.FieldByName(field)
|
||||
return b
|
||||
}
|
||||
|
||||
// StringInSlice checks if a slice contains a string.
|
||||
func StringInSlice(a string, list []string) (bool, int) {
|
||||
for i, b := range list {
|
||||
if b == a {
|
||||
return true, i
|
||||
}
|
||||
}
|
||||
return false, 0
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package variables
|
||||
|
||||
import "testing"
|
||||
|
||||
type testFieldInStructData struct {
|
||||
f1 string
|
||||
f2 bool
|
||||
f3 int
|
||||
f4 func()
|
||||
}
|
||||
|
||||
type testFieldInStruct struct {
|
||||
data interface{}
|
||||
field string
|
||||
result bool
|
||||
}
|
||||
|
||||
var testFieldInStructCases = []testFieldInStruct{
|
||||
{testFieldInStructData{}, "f1", true},
|
||||
{testFieldInStructData{}, "f2", true},
|
||||
{testFieldInStructData{}, "f3", true},
|
||||
{testFieldInStructData{}, "f4", true},
|
||||
{testFieldInStructData{}, "f5", false},
|
||||
{[]string{}, "", false},
|
||||
{map[string]int{"oi": 4}, "", false},
|
||||
{"asa", "", false},
|
||||
{"int", "", false},
|
||||
}
|
||||
|
||||
func TestFieldInStruct(t *testing.T) {
|
||||
for _, pair := range testFieldInStructCases {
|
||||
v := FieldInStruct(pair.data, pair.field)
|
||||
if v != pair.result {
|
||||
t.Error(
|
||||
"For", pair.data,
|
||||
"expected", pair.result,
|
||||
"got", v,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user