-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathcmd.go
133 lines (114 loc) · 3.25 KB
/
cmd.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package main
import (
"encoding/json"
"fmt"
"github.com/ghodss/yaml"
"io/ioutil"
"log"
"net/http"
"os/exec"
"path/filepath"
"regexp"
"strings"
)
type cmd struct {
Name string `json:"name"`
Args []string `json:"args"`
Paths []string `json:"paths"`
}
var cmds = []string{"ls", "mkdir", "rm", "mv", "cp"}
func (s *HTTPStaticServer) hCmd(w http.ResponseWriter, r *http.Request) {
data, _ := ioutil.ReadAll(r.Body)
log.Println(string(data))
c := cmd{}
if err := json.Unmarshal(data, &c); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// check command
if !canExec(c) {
http.Error(w, fmt.Sprintf("Forbidden, command: %s not allowed", c.Name), http.StatusForbidden)
return
}
//这里更安全期间,需要校验s.Root的路径,防止出现rm -rf /这种情况,但是在grapehttp启动时,已经
//校验过,所以这里就不用再校验
// check permission
for _, path := range c.Paths {
auth := s.readAccessConf(path, r)
// check access first
if auth.noAccess(r) {
log.Printf("%s have no access permission", c.Name)
http.Error(w, "access forbidden", http.StatusForbidden)
return
}
if !auth.canDelete(r) {
if c.Name == "rm" || c.Name == "mv" || c.Name == "cp" {
log.Printf("%s have no delete permission", c.Name)
http.Error(w, fmt.Sprintf("%s forbidden", c.Name), http.StatusForbidden)
return
}
}
if !auth.canUpload(r) {
if c.Name == "mkdir" || c.Name == "mv" || c.Name == "cp" {
log.Printf("%s have no delete permission", c.Name)
http.Error(w, fmt.Sprintf("%s forbidden", c.Name), http.StatusForbidden)
return
}
}
}
// complete Args
// absPath完全可用的path
// 这里加filepath.Clean是为了防止错误中出现//dir//file这样的不美观路径
absPaths := []string{}
for _, p := range c.Paths {
absPaths = append(absPaths, filepath.Clean(filepath.Join(s.Root, p)))
}
c.Args = append(c.Args, absPaths...)
cmd := exec.Command(c.Name, c.Args...)
bytes, _ := cmd.CombinedOutput()
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(strings.Replace(string(bytes), filepath.Clean(s.Root), "", 1)))
}
//生成权限控制文件
//默认所有人都有访问,上传,删除权限
func genGhs(dir string) error {
j := `{"upload":true,"delete":true,"noaccess":false}`
y, err := yaml.JSONToYAML([]byte(j))
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(dir, ".ghs.yml"), y, 0644)
if err != nil {
return err
}
return nil
}
func canExec(c cmd) bool {
for _, name := range cmds {
if name == c.Name {
return true
}
}
return false
}
func getUsage(root string) (string, error) {
command := exec.Command("df", "-hT", root)
out, err := command.CombinedOutput()
if err != nil {
return "", err
}
reg := regexp.MustCompile(".*%.*/.*")
for _, line := range strings.Split(string(out), "\n") {
if reg.MatchString(line) {
field := strings.Fields(line)
fstype := field[len(field)-6]
size := field[len(field)-5]
used := field[len(field)-4]
avail := field[len(field)-3]
use := field[len(field)-2]
mount := field[len(field)-1]
return fmt.Sprintf("Type(%s), Size(%s), Used(%s), Avail(%s), Use%%(%s), Mounted on(%s)", fstype, size, used, avail, use, mount), nil
}
}
return "", nil
}