Skip to content

Commit e1421f9

Browse files
committed
refactor(serverHandler): refine restrict access
- remove cache flag `restrictAccess` - add `Vary` header only when restrict access - filter restrict access data that only match current alias handler
1 parent e786617 commit e1421f9

File tree

12 files changed

+172
-59
lines changed

12 files changed

+172
-59
lines changed

src/param/helper.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,8 @@ func dedupPathValues(inputs []string) []string {
8080
return inputs
8181
}
8282

83-
values := inputs[1:]
84-
endIndex := 1
85-
eachValue:
86-
for i, length := 1, len(values); i < length; i++ {
87-
for j := 0; j < endIndex; j++ {
88-
if values[i] == values[j] {
89-
continue eachValue
90-
}
91-
}
92-
if endIndex != i {
93-
values[endIndex] = values[i]
94-
}
95-
endIndex++
96-
}
97-
98-
return inputs[:1+endIndex]
83+
values := util.InPlaceDedup(inputs[1:])
84+
return inputs[:1+len(values)]
9985
}
10086

10187
func dedupAllPathValues(inputs [][]string) {

src/param/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ func (param *Param) normalize() (errs []error) {
136136
// global restrict access, nil to disable, non-nil to enable with allowed hosts
137137
if param.GlobalRestrictAccess != nil {
138138
param.GlobalRestrictAccess = util.ExtractHostsFromUrls(param.GlobalRestrictAccess)
139+
param.GlobalRestrictAccess = util.InPlaceDedup(param.GlobalRestrictAccess)
139140
}
140141

141142
// restrict access

src/serverHandler/aliasHandler.go

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"mjpclab.dev/ghfs/src/serverLog"
77
"mjpclab.dev/ghfs/src/tpl/theme"
88
"mjpclab.dev/ghfs/src/user"
9+
"mjpclab.dev/ghfs/src/util"
910
"net/http"
1011
"regexp"
1112
"strconv"
@@ -14,8 +15,6 @@ import (
1415

1516
var defaultHandler = http.NotFoundHandler()
1617

17-
type prefixFilter func(whole, prefix string) bool
18-
1918
type aliasHandler struct {
2019
alias
2120

@@ -45,10 +44,9 @@ type aliasHandler struct {
4544
authUrls []string
4645
authDirs []string
4746

48-
restrictAccess bool
4947
globalRestrictAccess []string
50-
restrictAccessUrls []pathStrings
51-
restrictAccessDirs []pathStrings
48+
restrictAccessUrls pathStringsList
49+
restrictAccessDirs pathStringsList
5250

5351
globalHeaders [][2]string
5452
headersUrls []pathHeaders
@@ -114,7 +112,7 @@ func (h *aliasHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
114112

115113
if !session.allowAccess {
116114
if !h.applyMiddlewares(h.postMiddlewares, w, r, session, data) {
117-
h.page(w, r, data)
115+
h.page(w, r, session, data)
118116
}
119117
return
120118
}
@@ -174,7 +172,7 @@ func (h *aliasHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
174172
} else if shouldServeAsContent(session.file, data.Item) {
175173
h.content(w, r, session, data)
176174
} else {
177-
h.page(w, r, data)
175+
h.page(w, r, session, data)
178176
}
179177
}
180178

@@ -186,6 +184,11 @@ func newAliasHandler(
186184
) *aliasHandler {
187185
emptyRoot := p.EmptyRoot && currentAlias.url == "/"
188186

187+
globalRestrictAccess := p.GlobalRestrictAccess
188+
globalRestrictAccess = vhostCtx.restrictAccessUrls.mergePrefixMatched(globalRestrictAccess, util.HasUrlPrefixDir, currentAlias.url)
189+
globalRestrictAccess = vhostCtx.restrictAccessDirs.mergePrefixMatched(globalRestrictAccess, util.HasFsPrefixDir, currentAlias.fs)
190+
globalRestrictAccess = util.InPlaceDedup(globalRestrictAccess)
191+
189192
h := &aliasHandler{
190193
alias: currentAlias,
191194
emptyRoot: emptyRoot,
@@ -207,10 +210,9 @@ func newAliasHandler(
207210
authUrls: p.AuthUrls,
208211
authDirs: p.AuthDirs,
209212

210-
restrictAccess: vhostCtx.restrictAccess,
211-
globalRestrictAccess: p.GlobalRestrictAccess,
212-
restrictAccessUrls: vhostCtx.restrictAccessUrls,
213-
restrictAccessDirs: vhostCtx.restrictAccessDirs,
213+
globalRestrictAccess: globalRestrictAccess,
214+
restrictAccessUrls: vhostCtx.restrictAccessUrls.filterSuccessor(util.HasUrlPrefixDir, currentAlias.url),
215+
restrictAccessDirs: vhostCtx.restrictAccessDirs.filterSuccessor(util.HasFsPrefixDir, currentAlias.fs),
214216

215217
globalHeaders: p.GlobalHeaders,
216218
headersUrls: vhostCtx.headersUrls,

src/serverHandler/content.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77

88
func (h *aliasHandler) content(w http.ResponseWriter, r *http.Request, session *sessionContext, data *responseData) {
99
header := w.Header()
10-
header.Set("Vary", h.vary)
10+
header.Set("Vary", session.vary)
1111
header.Set("X-Content-Type-Options", "nosniff")
1212
if data.IsDownload {
1313
header.Set("Content-Disposition", "attachment; filename*=UTF-8''"+url.PathEscape(data.ItemName))

src/serverHandler/page.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ func updateTranslation(r *http.Request, data *responseData) {
6262
data.Trans = i18n.Dictionaries[index].Trans
6363
}
6464

65-
func (h *aliasHandler) page(w http.ResponseWriter, r *http.Request, data *responseData) {
65+
func (h *aliasHandler) page(w http.ResponseWriter, r *http.Request, session *sessionContext, data *responseData) {
6666
header := w.Header()
67-
header.Set("Vary", h.vary)
67+
header.Set("Vary", session.vary)
6868
header.Set("X-Content-Type-Options", "nosniff")
6969
header.Set("Content-Type", "text/html; charset=utf-8")
7070
if lacksHeader(header, "Cache-Control") {

src/serverHandler/pathValues.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package serverHandler
2+
3+
// prefixFilter
4+
5+
type prefixFilter func(whole, prefix string) bool
6+
7+
// pathStrings
8+
9+
type pathStrings struct {
10+
path string
11+
strings []string
12+
}
13+
14+
type pathStringsList []pathStrings
15+
16+
func (list pathStringsList) mergePrefixMatched(mergeWith []string, matchPrefix prefixFilter, refPath string) []string {
17+
var result []string
18+
if mergeWith != nil {
19+
result = make([]string, len(mergeWith))
20+
copy(result, mergeWith)
21+
}
22+
23+
for i := range list {
24+
if matchPrefix(refPath, list[i].path) {
25+
if result == nil {
26+
result = []string{}
27+
}
28+
result = append(result, list[i].strings...)
29+
}
30+
}
31+
32+
if mergeWith != nil && len(mergeWith) == len(result) {
33+
return mergeWith
34+
} else {
35+
return result
36+
}
37+
}
38+
39+
func (list pathStringsList) filterSuccessor(matchPrefix prefixFilter, refPath string) pathStringsList {
40+
var result pathStringsList
41+
42+
for i := range list {
43+
if len(list[i].path) > len(refPath) && matchPrefix(list[i].path, refPath) {
44+
result = append(result, list[i])
45+
}
46+
}
47+
48+
if len(list) == len(result) {
49+
return list
50+
} else {
51+
return result
52+
}
53+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package serverHandler
2+
3+
import (
4+
"mjpclab.dev/ghfs/src/util"
5+
"testing"
6+
)
7+
8+
func TestPathStrings(t *testing.T) {
9+
ps := pathStringsList{
10+
{"/a", []string{"a"}},
11+
{"/a/b", []string{"ab"}},
12+
{"/a/b/c", []string{"abc"}},
13+
{"/foo/bar", []string{"foobar"}},
14+
}
15+
16+
mergeWith := []string{"/xxx", "/yyy"}
17+
merged := ps.mergePrefixMatched(mergeWith, util.HasUrlPrefixDir, "/a/b")
18+
if len(mergeWith) != 2 {
19+
t.Error()
20+
}
21+
if len(merged) != 4 || merged[2] != "a" || merged[3] != "ab" {
22+
t.Error(merged)
23+
}
24+
25+
merged = ps.mergePrefixMatched(nil, util.HasUrlPrefixDir, "/lorem/ipsum")
26+
if merged != nil {
27+
t.Error(merged)
28+
}
29+
30+
successors := ps.filterSuccessor(util.HasUrlPrefixDir, "/a/b")
31+
if len(successors) != 1 || successors[0].path != "/a/b/c" {
32+
t.Error(successors)
33+
}
34+
}

src/serverHandler/restrictAccess.go

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,9 @@ func newRestrictAccesses(pathHostsList [][]string) []pathStrings {
2020
return restricts
2121
}
2222

23-
func hasRestrictAccess(globalRestrictAccesses []string, restrictAccessUrls, restrictAccessDirs []pathStrings) bool {
24-
return globalRestrictAccesses != nil || len(restrictAccessUrls) > 0 || len(restrictAccessDirs) > 0
25-
}
26-
27-
func (h *aliasHandler) isAllowAccess(r *http.Request, reqUrlPath, reqFsPath string, file *os.File, item os.FileInfo) bool {
28-
if !h.restrictAccess {
29-
return true
23+
func (h *aliasHandler) isAllowAccess(r *http.Request, reqUrlPath, reqFsPath string, file *os.File, item os.FileInfo) (restrict, allow bool) {
24+
if h.globalRestrictAccess == nil && len(h.restrictAccessUrls) == 0 && len(h.restrictAccessDirs) == 0 {
25+
return false, true
3026
}
3127

3228
reqHeader := r.Header
@@ -36,17 +32,17 @@ func (h *aliasHandler) isAllowAccess(r *http.Request, reqUrlPath, reqFsPath stri
3632
}
3733

3834
if len(sourceHost) == 0 && !shouldServeAsContent(file, item) {
39-
return true
35+
return true, true
4036
}
4137

4238
sourceHost = util.ExtractHostFromUrl(sourceHost)
4339
selfHost := strings.ToLower(r.Host)
4440
if sourceHost == selfHost {
45-
return true
41+
return true, true
4642
}
4743

4844
if util.Contains(h.globalRestrictAccess, sourceHost) {
49-
return true
45+
return true, true
5046
}
5147

5248
urlMatched := false
@@ -56,7 +52,7 @@ func (h *aliasHandler) isAllowAccess(r *http.Request, reqUrlPath, reqFsPath stri
5652
}
5753
urlMatched = true
5854
if util.Contains(h.restrictAccessUrls[i].strings, sourceHost) {
59-
return true
55+
return true, true
6056
}
6157
}
6258

@@ -67,13 +63,13 @@ func (h *aliasHandler) isAllowAccess(r *http.Request, reqUrlPath, reqFsPath stri
6763
}
6864
dirMatched = true
6965
if util.Contains(h.restrictAccessDirs[i].strings, sourceHost) {
70-
return true
66+
return true, true
7167
}
7268
}
7369

7470
if h.globalRestrictAccess == nil && !urlMatched && !dirMatched {
75-
return true
71+
return true, true
7672
}
7773

78-
return false
74+
return true, false
7975
}

src/serverHandler/sessionData.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ type sessionContext struct {
4848
authSuccess bool
4949

5050
redirectAction redirectAction
51+
vary string
52+
headers [][2]string
5153

52-
headers [][2]string
5354
wantJson bool
54-
file *os.File
55+
56+
file *os.File
5557

5658
errors []error
5759
}
@@ -406,7 +408,11 @@ func (h *aliasHandler) getSessionData(r *http.Request) (session *sessionContext,
406408
}
407409
}
408410

409-
allowAccess := h.isAllowAccess(r, vhostReqPath, fsPath, file, item)
411+
restrictAccess, allowAccess := h.isAllowAccess(r, vhostReqPath, fsPath, file, item)
412+
vary := h.vary
413+
if restrictAccess {
414+
vary += ", referer, origin"
415+
}
410416
if !allowAccess {
411417
status = http.StatusForbidden
412418
}
@@ -467,17 +473,19 @@ func (h *aliasHandler) getSessionData(r *http.Request) (session *sessionContext,
467473

468474
allowAccess: allowAccess,
469475

470-
redirectAction: redirectAction,
471-
472476
needAuth: needAuth,
473477
requestAuth: requestAuth,
474478
authUserId: authUserId,
475479
authUserName: authUserName,
476480
authSuccess: authSuccess,
477481

478-
headers: headers,
482+
redirectAction: redirectAction,
483+
vary: vary,
484+
headers: headers,
485+
479486
wantJson: wantJson,
480-
file: file,
487+
488+
file: file,
481489

482490
errors: errs,
483491
}

src/serverHandler/vhostHandler.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ type vhostContext struct {
2222
hideDirs *regexp.Regexp
2323
hideFiles *regexp.Regexp
2424

25-
restrictAccess bool
26-
restrictAccessUrls []pathStrings
27-
restrictAccessDirs []pathStrings
25+
restrictAccessUrls pathStringsList
26+
restrictAccessDirs pathStringsList
2827

2928
headersUrls []pathHeaders
3029
headersDirs []pathHeaders
@@ -79,13 +78,9 @@ func NewVhostHandler(
7978
// restrict access
8079
restrictAccessUrls := newRestrictAccesses(p.RestrictAccessUrls)
8180
restrictAccessDirs := newRestrictAccesses(p.RestrictAccessDirs)
82-
restrictAccess := hasRestrictAccess(p.GlobalRestrictAccess, restrictAccessUrls, restrictAccessDirs)
8381

8482
// `Vary` header
8583
vary := "accept-encoding"
86-
if restrictAccess {
87-
vary += ", referer, origin"
88-
}
8984

9085
// alias param
9186
vhostCtx := &vhostContext{
@@ -100,7 +95,6 @@ func NewVhostHandler(
10095
hideDirs: hideDirs,
10196
hideFiles: hideFiles,
10297

103-
restrictAccess: restrictAccess,
10498
restrictAccessUrls: restrictAccessUrls,
10599
restrictAccessDirs: restrictAccessDirs,
106100

0 commit comments

Comments
 (0)