fix: align CHFS directory rule inheritance
This commit is contained in:
@@ -67,16 +67,16 @@ func main() {
|
|||||||
for _, ac := range cfg.Accounts {
|
for _, ac := range cfg.Accounts {
|
||||||
a := &auth.Account{Username: ac.Username, Password: ac.Password, Mask: auth.ParseMask(ac.Default)}
|
a := &auth.Account{Username: ac.Username, Password: ac.Password, Mask: auth.ParseMask(ac.Default)}
|
||||||
for _, d := range ac.None {
|
for _, d := range ac.None {
|
||||||
a.Rules = append(a.Rules, auth.PathRule{Dir: d, Deny: true})
|
a.Rules = append(a.Rules, auth.PathRule{Dir: accountRulePath(d, cfg.Path), Deny: true})
|
||||||
}
|
}
|
||||||
for _, d := range ac.Read {
|
for _, d := range ac.Read {
|
||||||
a.Rules = append(a.Rules, auth.PathRule{Dir: d, Mask: auth.Read, ChildrenOnly: true})
|
a.Rules = append(a.Rules, auth.PathRule{Dir: accountRulePath(d, cfg.Path), Mask: auth.Read, ChildrenOnly: true})
|
||||||
}
|
}
|
||||||
for _, d := range ac.Write {
|
for _, d := range ac.Write {
|
||||||
a.Rules = append(a.Rules, auth.PathRule{Dir: d, Mask: auth.ParseMask("w"), ChildrenOnly: true})
|
a.Rules = append(a.Rules, auth.PathRule{Dir: accountRulePath(d, cfg.Path), Mask: auth.ParseMask("w"), ChildrenOnly: true})
|
||||||
}
|
}
|
||||||
for _, d := range ac.Delete {
|
for _, d := range ac.Delete {
|
||||||
a.Rules = append(a.Rules, auth.PathRule{Dir: d, Mask: auth.ParseMask("d"), ChildrenOnly: true})
|
a.Rules = append(a.Rules, auth.PathRule{Dir: accountRulePath(d, cfg.Path), Mask: auth.ParseMask("d"), ChildrenOnly: true})
|
||||||
}
|
}
|
||||||
if ac.Username == "guest" {
|
if ac.Username == "guest" {
|
||||||
mgr.Guest = a
|
mgr.Guest = a
|
||||||
@@ -103,6 +103,29 @@ type multiFlag []string
|
|||||||
func (m *multiFlag) String() string { return strings.Join(*m, "|") }
|
func (m *multiFlag) String() string { return strings.Join(*m, "|") }
|
||||||
func (m *multiFlag) Set(v string) error { *m = append(*m, v); return nil }
|
func (m *multiFlag) Set(v string) error { *m = append(*m, v); return nil }
|
||||||
|
|
||||||
|
func accountRulePath(rule string, roots []string) string {
|
||||||
|
rule = strings.TrimSpace(strings.Trim(rule, "\\\""))
|
||||||
|
if rule == "" {
|
||||||
|
return rule
|
||||||
|
}
|
||||||
|
rule = filepath.ToSlash(rule)
|
||||||
|
if !filepath.IsAbs(rule) {
|
||||||
|
return strings.Trim(rule, "/")
|
||||||
|
}
|
||||||
|
for _, root := range roots {
|
||||||
|
r := filepath.Clean(root)
|
||||||
|
rel, err := filepath.Rel(r, rule)
|
||||||
|
if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if rel == "." {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return filepath.ToSlash(rel)
|
||||||
|
}
|
||||||
|
return rule
|
||||||
|
}
|
||||||
|
|
||||||
func itoa(n int) string {
|
func itoa(n int) string {
|
||||||
const d = "0123456789"
|
const d = "0123456789"
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ func (s *Server) files(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out = append(out, fileInfo{Name: fi.Name(), Path: fp, Size: fi.Size(), Modified: originalTime(fi.ModTime()), Dir: fi.IsDir(), Mask: permString(a.MaskFor(fp)), GuestMask: permString(s.Auth.Guest.MaskFor(fp)), HasSubDir: sub, Icon: iconFor(fi)})
|
out = append(out, fileInfo{Name: fi.Name(), Path: fp, Size: fi.Size(), Modified: originalTime(fi.ModTime()), Dir: fi.IsDir(), Mask: permString(a.MaskForEntry(fp)), GuestMask: permString(s.Auth.Guest.MaskForEntry(fp)), HasSubDir: sub, Icon: iconFor(fi)})
|
||||||
}
|
}
|
||||||
virtual := p == "" && s.MultiRoot
|
virtual := p == "" && s.MultiRoot
|
||||||
writeJSON(w, map[string]any{"files": out, "currentMask": permString(m), "virtualRoot": virtual})
|
writeJSON(w, map[string]any{"files": out, "currentMask": permString(m), "virtualRoot": virtual})
|
||||||
@@ -483,7 +483,7 @@ func (s *Server) search(w http.ResponseWriter, r *http.Request) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if needle == "" || strings.Contains(strings.ToLower(fi.Name()), needle) {
|
if needle == "" || strings.Contains(strings.ToLower(fi.Name()), needle) {
|
||||||
out = append(out, fileInfo{Name: fi.Name(), Path: "/" + strings.Trim(p, "/"), Size: fi.Size(), Modified: originalTime(fi.ModTime()), Dir: fi.IsDir(), Mask: permString(a.MaskFor(p)), GuestMask: permString(s.Auth.Guest.MaskFor(p)), HasSubDir: false, Icon: iconFor(fi)})
|
out = append(out, fileInfo{Name: fi.Name(), Path: "/" + strings.Trim(p, "/"), Size: fi.Size(), Modified: originalTime(fi.ModTime()), Dir: fi.IsDir(), Mask: permString(a.MaskForEntry(p)), GuestMask: permString(s.Auth.Guest.MaskForEntry(p)), HasSubDir: false, Icon: iconFor(fi)})
|
||||||
}
|
}
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
if err := walk(p); err != nil {
|
if err := walk(p); err != nil {
|
||||||
|
|||||||
@@ -89,6 +89,18 @@ func (m *Manager) Authenticate(user, pwd string) *Account {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (a *Account) MaskFor(path string) PermMask {
|
func (a *Account) MaskFor(path string) PermMask {
|
||||||
|
return a.maskFor(path, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MaskForEntry returns the permission shown for a directory/file while its
|
||||||
|
// parent directory is being listed. CHFS section rules rule.r/rule.w/rule.d
|
||||||
|
// affect the contents of the named directory, but the directory entry itself
|
||||||
|
// keeps the inherited permission until it is opened.
|
||||||
|
func (a *Account) MaskForEntry(path string) PermMask {
|
||||||
|
return a.maskFor(path, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Account) maskFor(path string, entry bool) PermMask {
|
||||||
path = strings.Trim(path, "/")
|
path = strings.Trim(path, "/")
|
||||||
best := -1
|
best := -1
|
||||||
mask := a.Mask
|
mask := a.Mask
|
||||||
@@ -97,7 +109,7 @@ func (a *Account) MaskFor(path string) PermMask {
|
|||||||
if !matchPath(d, path) {
|
if !matchPath(d, path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if r.ChildrenOnly && matchPathExact(d, path) {
|
if entry && r.ChildrenOnly && matchPathExact(d, path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(d) > best {
|
if len(d) > best {
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ func TestPathRuleSemantics(t *testing.T) {
|
|||||||
{"", "R"},
|
{"", "R"},
|
||||||
{"private", ""},
|
{"private", ""},
|
||||||
{"private/x.txt", ""},
|
{"private/x.txt", ""},
|
||||||
{"share", "R"},
|
{"share", "RW"},
|
||||||
{"share/x.txt", "RW"},
|
{"share/x.txt", "RW"},
|
||||||
{"drop", "R"},
|
{"drop", "RWD"},
|
||||||
{"drop/x.txt", "RWD"},
|
{"drop/x.txt", "RWD"},
|
||||||
{"public/x.txt", "R"},
|
{"public/x.txt", "R"},
|
||||||
{"public/sub/x.txt", "R"},
|
{"public/sub/x.txt", "R"},
|
||||||
|
|||||||
Reference in New Issue
Block a user