Skip to content

Commit 43cb263

Browse files
committed
support .ghs.yml add google analytics
1 parent 2a229b8 commit 43cb263

File tree

7 files changed

+118
-29
lines changed

7 files changed

+118
-29
lines changed

.fsw.yml

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ desc: Auto generated by fswatch [gohttp-vue]
22
triggers:
33
- name: ""
44
pattens:
5+
- '!.git/'
56
- '**/*.go'
67
- '**/*.tmpl.html'
78
env:

README.md

+20-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Upload size now limited to 1G
4141
1. [x] Hidden work `download` and `qrcode` in small screen
4242
1. [x] Theme select support
4343
1. [x] OK to working behide Nginx
44-
1. [ ] \.htaccess support
44+
1. [ ] \.ghs.yml support (like \.htaccess)
4545
1. [ ] Calculate md5sum and sha
4646
1. [ ] Folder upload
4747
1. [ ] Support sort by size or modified time
@@ -64,6 +64,25 @@ Listen port 8000 on all interface, and enable upload
6464
./gohttpserver -r ./ --addr :8000 --upload
6565
```
6666

67+
## Advanced usage
68+
Support update access rule if there is a file named `.ghs.yml` under directory. `.ghs.yml` example
69+
70+
```yaml
71+
---
72+
upload: false
73+
```
74+
75+
For example, if there is such file under directory `foo`, directory `foo` can not be uploaded, while `bar` can't.
76+
77+
```
78+
root -
79+
|-- foo
80+
| |-- .ghs.yml
81+
| `-- world.txt
82+
`-- bar
83+
`-- hello.txt
84+
```
85+
6786
### ipa plist proxy
6887
This is used for server which not https enabled. default use <https://plistproxy.herokuapp.com/plist>
6988

httpstaticserver.go

+53-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"strings"
1515
"time"
1616

17+
"github.com/go-yaml/yaml"
1718
"github.com/gorilla/mux"
1819
)
1920

@@ -23,11 +24,12 @@ type IndexFileItem struct {
2324
}
2425

2526
type HTTPStaticServer struct {
26-
Root string
27-
Theme string
28-
Upload bool
29-
Title string
30-
PlistProxy string
27+
Root string
28+
Theme string
29+
Upload bool
30+
Title string
31+
PlistProxy string
32+
GoogleTrackerId string
3133

3234
indexes []IndexFileItem
3335
m *mux.Router
@@ -41,7 +43,7 @@ func NewHTTPStaticServer(root string) *HTTPStaticServer {
4143
if !strings.HasSuffix(root, "/") {
4244
root = root + "/"
4345
}
44-
log.Printf("Root path: %s\n", root)
46+
log.Printf("root path: %s\n", root)
4547
m := mux.NewRouter()
4648
s := &HTTPStaticServer{
4749
Root: root,
@@ -50,10 +52,12 @@ func NewHTTPStaticServer(root string) *HTTPStaticServer {
5052
}
5153

5254
go func() {
55+
time.Sleep(1 * time.Second)
5356
for {
54-
log.Println("making fs index ...")
57+
startTime := time.Now()
58+
log.Println("Started making search index")
5559
s.makeIndex()
56-
log.Println("indexing finished, next index after 10 minutes")
60+
log.Printf("Completed search index in %v", time.Since(startTime))
5761
//time.Sleep(time.Second * 1)
5862
time.Sleep(time.Minute * 10)
5963
}
@@ -101,6 +105,15 @@ func (s *HTTPStaticServer) hStatus(w http.ResponseWriter, r *http.Request) {
101105
}
102106

103107
func (s *HTTPStaticServer) hUpload(w http.ResponseWriter, req *http.Request) {
108+
path := mux.Vars(req)["path"]
109+
110+
// check auth
111+
auth := s.readAccessConf(path)
112+
if !auth.Upload {
113+
http.Error(w, "Upload forbidden", http.StatusForbidden)
114+
return
115+
}
116+
104117
err := req.ParseMultipartForm(1 << 30) // max memory 1G
105118
if err != nil {
106119
http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -111,7 +124,6 @@ func (s *HTTPStaticServer) hUpload(w http.ResponseWriter, req *http.Request) {
111124
return
112125
}
113126

114-
path := mux.Vars(req)["path"]
115127
dirpath := filepath.Join(s.Root, path)
116128

117129
for _, mfile := range req.MultipartForm.File["file"] {
@@ -263,6 +275,10 @@ type ListResponse struct {
263275
Size string `json:"size"`
264276
}
265277

278+
type AccessConf struct {
279+
Upload bool `yaml:"upload" json:"upload"`
280+
}
281+
266282
func (s *HTTPStaticServer) hJSONList(w http.ResponseWriter, r *http.Request) {
267283
requestPath := mux.Vars(r)["path"]
268284
localPath := filepath.Join(s.Root, requestPath)
@@ -292,6 +308,7 @@ func (s *HTTPStaticServer) hJSONList(w http.ResponseWriter, r *http.Request) {
292308
}
293309
}
294310

311+
// turn file list -> json
295312
lrs := make([]ListResponse, 0)
296313
for path, info := range fileInfoMap {
297314
lr := ListResponse{
@@ -318,7 +335,10 @@ func (s *HTTPStaticServer) hJSONList(w http.ResponseWriter, r *http.Request) {
318335
lrs = append(lrs, lr)
319336
}
320337

321-
data, _ := json.Marshal(lrs)
338+
data, _ := json.Marshal(map[string]interface{}{
339+
"files": lrs,
340+
"auth": s.readAccessConf(requestPath),
341+
})
322342
w.Header().Set("Content-Type", "application/json")
323343
w.Write(data)
324344
}
@@ -366,6 +386,29 @@ func (s *HTTPStaticServer) findIndex(text string) []IndexFileItem {
366386
return ret
367387
}
368388

389+
func (s *HTTPStaticServer) defaultAccessConf() AccessConf {
390+
return AccessConf{
391+
Upload: s.Upload,
392+
}
393+
}
394+
395+
func (s *HTTPStaticServer) readAccessConf(requestPath string) (ac AccessConf) {
396+
ac = s.defaultAccessConf()
397+
cfgFile := filepath.Join(s.Root, requestPath, ".ghs.yml")
398+
data, err := ioutil.ReadFile(cfgFile)
399+
if err != nil {
400+
if os.IsNotExist(err) {
401+
return
402+
}
403+
log.Printf("Err read .ghs.yml: %v", err)
404+
}
405+
err = yaml.Unmarshal(data, &ac)
406+
if err != nil {
407+
log.Printf("Err format .ghs.yml: %v", err)
408+
}
409+
return
410+
}
411+
369412
func deepPath(basedir, name string) string {
370413
isDir := true
371414
// loop max 5, incase of for loop not finished

main.go

+19-13
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,25 @@ import (
1818
)
1919

2020
type Configure struct {
21-
Addr string
22-
Root string
23-
HttpAuth string
24-
Cert string
25-
Key string
26-
Cors bool
27-
Theme string
28-
XHeaders bool
29-
Upload bool
30-
PlistProxy *url.URL
31-
Title string
21+
Addr string
22+
Root string
23+
HttpAuth string
24+
Cert string
25+
Key string
26+
Cors bool
27+
Theme string
28+
XHeaders bool
29+
Upload bool
30+
PlistProxy *url.URL
31+
Title string
32+
GoogleTrackerId string
3233
}
3334

3435
type logger struct {
3536
}
3637

3738
func (l logger) Log(record accesslog.LogRecord) {
38-
log.Printf("%s [code %d] %s", record.Method, record.Status, record.Uri)
39+
log.Printf("%s - %s %d %s", record.Ip, record.Method, record.Status, record.Uri)
3940
}
4041

4142
var (
@@ -83,6 +84,7 @@ func parseFlags() {
8384
kingpin.Flag("cors", "enable cross-site HTTP request").BoolVar(&gcfg.Cors)
8485
kingpin.Flag("plistproxy", "plist proxy when server is not https").Default(defaultPlistProxy).Short('p').URLVar(&gcfg.PlistProxy)
8586
kingpin.Flag("title", "server title").Default("Go HTTP File Server").StringVar(&gcfg.Title)
87+
kingpin.Flag("google-tracker-id", "set to empty to disable it").Default("UA-81205425-2").StringVar(&gcfg.GoogleTrackerId)
8688

8789
kingpin.Parse()
8890
}
@@ -93,6 +95,7 @@ func main() {
9395
ss := NewHTTPStaticServer(gcfg.Root)
9496
ss.Theme = gcfg.Theme
9597
ss.Title = gcfg.Title
98+
ss.GoogleTrackerId = gcfg.GoogleTrackerId
9699

97100
if gcfg.Upload {
98101
ss.EnableUpload()
@@ -129,7 +132,10 @@ func main() {
129132
w.Write(data)
130133
})
131134

132-
log.Printf("Listening on addr: %s\n", strconv.Quote(gcfg.Addr))
135+
if !strings.Contains(gcfg.Addr, ":") {
136+
gcfg.Addr = ":" + gcfg.Addr
137+
}
138+
log.Printf("listening on %s\n", strconv.Quote(gcfg.Addr))
133139

134140
var err error
135141
if gcfg.Key != "" && gcfg.Cert != "" {

res/index.tmpl.html

+19-3
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,9 @@
6767
<button class="btn btn-xs btn-default" v-on:click='toggleHidden()'>
6868
Show hidden <i class="fa" v-bind:class='showHidden ? "fa-eye" : "fa-eye-slash"'></i>
6969
</button>
70-
[[ if .Upload ]]
71-
<button class="btn btn-xs btn-default" data-toggle="modal" data-target="#upload-modal">
70+
<button class="btn btn-xs btn-default" v-if="auth.upload" data-toggle="modal" data-target="#upload-modal">
7271
Upload file <i class="fa fa-upload"></i>
7372
</button>
74-
[[ end ]]
7573
</td>
7674
</tr>
7775
<tr>
@@ -179,6 +177,24 @@ <h4 class="modal-title">
179177
<script src="/-/res/js/dropzone.js"></script>
180178
<script src="/-/res/bootstrap-3.3.5/js/bootstrap.min.js"></script>
181179
<script src="/-/res/js/index.js"></script>
180+
[[if .GoogleTrackerId ]]
181+
<script>
182+
(function(i, s, o, g, r, a, m) {
183+
i['GoogleAnalyticsObject'] = r;
184+
i[r] = i[r] || function() {
185+
(i[r].q = i[r].q || []).push(arguments)
186+
}, i[r].l = 1 * new Date();
187+
a = s.createElement(o),
188+
m = s.getElementsByTagName(o)[0];
189+
a.async = 1;
190+
a.src = g;
191+
m.parentNode.insertBefore(a, m)
192+
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
193+
194+
ga('create', '[[.GoogleTrackerId]]', 'auto');
195+
ga('send', 'pageview');
196+
</script>
197+
[[ end ]]
182198
</body>
183199

184200
</html>

res/js/index.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var vm = new Vue({
2727
showHidden: false,
2828
previewFile: null,
2929
version: "loading",
30+
auth: {},
3031
search: getQueryString("search"),
3132
files: [{
3233
name: "loading ...",
@@ -200,13 +201,14 @@ function loadFileList(pathname) {
200201
dataType: "json",
201202
cache: false,
202203
success: function(res) {
203-
res.sort(function(a, b) {
204+
res.files.sort(function(a, b) {
204205
var obj2n = function(v) {
205206
return v.type == "dir" ? 0 : 1;
206207
}
207208
return obj2n(a) - obj2n(b);
208209
})
209-
vm.files = res;
210+
vm.files = res.files;
211+
vm.auth = res.auth;
210212
},
211213
error: function(err) {
212214
console.error(err)

testdata/uploadable/.ghs.yml

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
upload: true

0 commit comments

Comments
 (0)