Skip to content

Commit

Permalink
support folder delete, prevent ghs.yml see
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed Sep 18, 2018
1 parent 40f02fb commit 0cacad2
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 10 deletions.
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ If using go1.5, ensure you set GO15VENDOREXPERIMENT=1
1. [x] All assets package to Standalone binary
1. [x] Different file type different icon
1. [x] Support show or hide hidden files
1. [x] Upload support (for security reason, you need enabled it by option `--upload`)
1. [x] Upload support (auth by token or session)
1. [x] README.md preview
1. [x] HTTP Basic Auth
1. [x] Partial reload pages when directory change
Expand Down Expand Up @@ -93,6 +93,18 @@ Listen on port 8000 of all interfaces, and enable file uploading.

The openid returns url using "http" instead of "https", but I am not planing to fix this currently.

- Enable upload

```sh
$ gohttpserver --upload
```

- Enable delete and Create folder

```sh
$ gohttpserver --delete
```

## Advanced usage
Add access rule by creating a `.ghs.yml` file under a sub-directory. An example:

Expand All @@ -104,10 +116,13 @@ users:
- email: "codeskyblue@codeskyblue.com"
delete: true
upload: true
token: 4567gf8asydhf293r23r
```

In this case, if openid auth is enabled and user "codeskyblue@codeskyblue.com" has logged in, he/she can delete/upload files under the directory where the `.ghs.yml` file exits.

`token` is used for upload. see [upload with curl](#upload-with-curl)

For example, in the following directory hierarchy, users can delete/uploade files in directory `foo`, but he/she cannot do this in directory `bar`.

```
Expand Down Expand Up @@ -154,6 +169,10 @@ For example, upload a file named `foo.txt` to directory `somedir`

```sh
$ curl -F file=@foo.txt localhost:8000/somedir
{"destination":"somedir/foo.txt","success":true}
# upload with token
$ curl -F file=@foo.txt -F token=12312jlkjafs localhost:8000/somedir
{"destination":"somedir/foo.txt","success":true}
```

## FAQ
Expand Down
5 changes: 4 additions & 1 deletion assets/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@
<span class="hidden-xs">Archive</span> Zip
<span class="glyphicon glyphicon-download-alt"></span>
</a>
<button class="btn btn-default btn-xs" v-if="auth.delete" v-on:click="deletePathConfirm(f, $event)">
<span style="color:#CC3300" class="glyphicon glyphicon-trash"></span>
</button>
</template>
<template v-if="f.type == 'file'">
<a class="btn btn-default btn-xs hidden-xs" href="/{{f.path}}?download=true">
Expand Down Expand Up @@ -232,7 +235,7 @@ <h4 class="modal-title">
<div class="col-md-12">
<div id="footer" class="pull-right" style="margin: 2em 1em">
<a href="https://github.com/codeskyblue/gohttpserver">gohttpserver (ver:{{version}})</a>, written by <a href="https://github.com/codeskyblue">codeskyblue</a>.
Copyright 2016-2017. go1.7
Copyright 2016-2018. go1.10
</div>
</div>
</div>
Expand Down
4 changes: 3 additions & 1 deletion assets/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,10 @@ var vm = new Vue({
})
},
deletePathConfirm: function (f, e) {
// confirm
e.preventDefault();
if (!window.confirm("Delete " + f.name + " ?")) {
return;
}
$.ajax({
url: pathJoin([location.pathname, f.name]),
method: 'DELETE',
Expand Down
51 changes: 46 additions & 5 deletions httpstaticserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"github.com/shogo82148/androidbinary/apk"
)

const YAMLCONF = ".ghs.yml"

type ApkInfo struct {
PackageName string `json:"packageName"`
MainActivity string `json:"mainActivity"`
Expand Down Expand Up @@ -104,13 +106,20 @@ func (s *HTTPStaticServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (s *HTTPStaticServer) hIndex(w http.ResponseWriter, r *http.Request) {
path := mux.Vars(r)["path"]
relPath := filepath.Join(s.Root, path)
log.Println("Get", path, relPath)
log.Println("GET", path, relPath)
if r.FormValue("raw") == "false" || isDir(relPath) {
if r.Method == "HEAD" {
return
}
renderHTML(w, "index.html", s)
} else {
if filepath.Base(path) == YAMLCONF {
auth := s.readAccessConf(path)
if !auth.Delete {
http.Error(w, "Security warning, not allowed to read", http.StatusForbidden)
return
}
}
if r.FormValue("download") == "true" {
w.Header().Set("Content-Disposition", "attachment; filename="+strconv.Quote(filepath.Base(path)))
}
Expand All @@ -132,6 +141,10 @@ func (s *HTTPStaticServer) hMkdir(w http.ResponseWriter, req *http.Request) {
return
}
name := req.FormValue("name")
if strings.ContainsAny(name, "\\/:*<>|") {
http.Error(w, "Name should not contains \\/:*<>|", http.StatusForbidden)
return
}
err := os.Mkdir(filepath.Join(s.Root, path, name), 0755)
if err != nil {
http.Error(w, err.Error(), 500)
Expand Down Expand Up @@ -397,6 +410,7 @@ type UserControl struct {
// Access bool
Upload bool
Delete bool
Token string
}

type AccessConf struct {
Expand Down Expand Up @@ -444,7 +458,20 @@ func (c *AccessConf) canDelete(r *http.Request) bool {
return c.Delete
}

func (c *AccessConf) canUploadByToken(token string) bool {
for _, rule := range c.Users {
if rule.Token == token {
return rule.Upload
}
}
return c.Upload
}

func (c *AccessConf) canUpload(r *http.Request) bool {
token := r.FormValue("token")
if token != "" {
return c.canUploadByToken(token)
}
session, err := store.Get(r, defaultSessionName)
if err != nil {
return c.Upload
Expand All @@ -454,6 +481,7 @@ func (c *AccessConf) canUpload(r *http.Request) bool {
return c.Upload
}
userInfo := val.(*UserInfo)

for _, rule := range c.Users {
if rule.Email == userInfo.Email {
return rule.Upload
Expand Down Expand Up @@ -616,7 +644,7 @@ func (s *HTTPStaticServer) readAccessConf(requestPath string) (ac AccessConf) {
if isFile(relPath) {
relPath = filepath.Dir(relPath)
}
cfgFile := filepath.Join(relPath, ".ghs.yml")
cfgFile := filepath.Join(relPath, YAMLCONF)
data, err := ioutil.ReadFile(cfgFile)
if err != nil {
if os.IsNotExist(err) {
Expand Down Expand Up @@ -671,7 +699,11 @@ func assetsContent(name string) string {
return string(data)
}

var _tmpl *template.Template
// TODO: I need to read more abouthtml/template
var (
_tmpl *template.Template
_parsed = make(map[string]bool)
)

func _parseTemplate(name, content string) {
if _tmpl == nil {
Expand All @@ -684,9 +716,18 @@ func _parseTemplate(name, content string) {
t = _tmpl.New(name)
}
template.Must(t.New(name).Delims("[[", "]]").Parse(content))
_parsed[name] = true
}

func renderHTML(w http.ResponseWriter, name string, v interface{}) {
t := template.Must(template.New("index.html").Delims("[[", "]]").Parse(assetsContent("/index.html")))
t.Execute(w, v)
if _, ok := Assets.(http.Dir); ok {
log.Println("Hot load", name)
t := template.Must(template.New(name).Delims("[[", "]]").Parse(assetsContent(name)))
t.Execute(w, v)
} else {
if !_parsed[name] {
_parseTemplate(name, assetsContent(name))
}
_tmpl.ExecuteTemplate(w, name, v)
}
}
5 changes: 3 additions & 2 deletions testdata/uploadable/.ghs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
upload: true
upload: false
users:
- email: "user@example.com"
upload: true
delete: true
delete: true
token: 123456
3 changes: 3 additions & 0 deletions zip.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ func CompressToZip(w http.ResponseWriter, rootDir string) {

filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
zipPath := path[len(rootDir):]
if info.Name() == YAMLCONF { // ignore .ghs.yml for security
return nil
}
return zw.Add(zipPath, path)
})
}
Expand Down

0 comments on commit 0cacad2

Please sign in to comment.