mirror of
https://github.com/go-gitea/gitea.git
synced 2025-02-02 15:09:33 -05:00
Add basic auth support to rss/atom feeds (#33371)
Allows RSS readers to access private feeds using their basic auth capabilities. Not all clients feature the ability to add cookies or headers. fixes #32458 Tested with miniflux no credentials: ![image](https://github.com/user-attachments/assets/8c3369f2-1cf6-4ce3-ac6e-84447e454928) basic auth entered: ![image](https://github.com/user-attachments/assets/c93ff22c-1429-4a80-898f-91d9f35c7c61) ![image](https://github.com/user-attachments/assets/60d83afd-9dde-4973-a440-ff8138799e87) --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
26b51aa032
commit
c79adf00b8
@ -26,13 +26,17 @@ type globalVarsStruct struct {
|
||||
gitRawOrAttachPathRe *regexp.Regexp
|
||||
lfsPathRe *regexp.Regexp
|
||||
archivePathRe *regexp.Regexp
|
||||
feedPathRe *regexp.Regexp
|
||||
feedRefPathRe *regexp.Regexp
|
||||
}
|
||||
|
||||
var globalVars = sync.OnceValue(func() *globalVarsStruct {
|
||||
return &globalVarsStruct{
|
||||
gitRawOrAttachPathRe: regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/(?:(?:git-(?:(?:upload)|(?:receive))-pack$)|(?:info/refs$)|(?:HEAD$)|(?:objects/)|(?:raw/)|(?:releases/download/)|(?:attachments/))`),
|
||||
lfsPathRe: regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/info/lfs/`),
|
||||
archivePathRe: regexp.MustCompile(`^/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+/archive/`),
|
||||
gitRawOrAttachPathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/(?:(?:git-(?:(?:upload)|(?:receive))-pack$)|(?:info/refs$)|(?:HEAD$)|(?:objects/)|(?:raw/)|(?:releases/download/)|(?:attachments/))`),
|
||||
lfsPathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/info/lfs/`),
|
||||
archivePathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/archive/`),
|
||||
feedPathRe: regexp.MustCompile(`^/[-.\w]+(/[-.\w]+)?\.(rss|atom)$`), // "/owner.rss" or "/owner/repo.atom"
|
||||
feedRefPathRe: regexp.MustCompile(`^/[-.\w]+/[-.\w]+/(rss|atom)/`), // "/owner/repo/rss/branch/..."
|
||||
}
|
||||
})
|
||||
|
||||
@ -61,6 +65,16 @@ func (a *authPathDetector) isAttachmentDownload() bool {
|
||||
return strings.HasPrefix(a.req.URL.Path, "/attachments/") && a.req.Method == "GET"
|
||||
}
|
||||
|
||||
func (a *authPathDetector) isFeedRequest(req *http.Request) bool {
|
||||
if !setting.Other.EnableFeed {
|
||||
return false
|
||||
}
|
||||
if req.Method != "GET" {
|
||||
return false
|
||||
}
|
||||
return a.vars.feedPathRe.MatchString(req.URL.Path) || a.vars.feedRefPathRe.MatchString(req.URL.Path)
|
||||
}
|
||||
|
||||
// isContainerPath checks if the request targets the container endpoint
|
||||
func (a *authPathDetector) isContainerPath() bool {
|
||||
return strings.HasPrefix(a.req.URL.Path, "/v2/")
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@ -92,6 +93,19 @@ func Test_isGitRawOrLFSPath(t *testing.T) {
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
defer test.MockVariableValue(&setting.LFS.StartServer)()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.path, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("POST", "http://localhost"+tt.path, nil)
|
||||
setting.LFS.StartServer = false
|
||||
assert.Equal(t, tt.want, newAuthPathDetector(req).isGitRawOrAttachOrLFSPath())
|
||||
|
||||
setting.LFS.StartServer = true
|
||||
assert.Equal(t, tt.want, newAuthPathDetector(req).isGitRawOrAttachOrLFSPath())
|
||||
})
|
||||
}
|
||||
|
||||
lfsTests := []string{
|
||||
"/owner/repo/info/lfs/",
|
||||
"/owner/repo/info/lfs/objects/batch",
|
||||
@ -103,19 +117,6 @@ func Test_isGitRawOrLFSPath(t *testing.T) {
|
||||
"/owner/repo/info/lfs/locks/verify",
|
||||
"/owner/repo/info/lfs/locks/123/unlock",
|
||||
}
|
||||
|
||||
origLFSStartServer := setting.LFS.StartServer
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.path, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("POST", "http://localhost"+tt.path, nil)
|
||||
setting.LFS.StartServer = false
|
||||
assert.Equal(t, tt.want, newAuthPathDetector(req).isGitRawOrAttachOrLFSPath())
|
||||
|
||||
setting.LFS.StartServer = true
|
||||
assert.Equal(t, tt.want, newAuthPathDetector(req).isGitRawOrAttachOrLFSPath())
|
||||
})
|
||||
}
|
||||
for _, tt := range lfsTests {
|
||||
t.Run(tt, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("POST", tt, nil)
|
||||
@ -128,5 +129,27 @@ func Test_isGitRawOrLFSPath(t *testing.T) {
|
||||
assert.Equalf(t, setting.LFS.StartServer, got, "isGitOrLFSPath(%q) = %v, want %v", tt, got, setting.LFS.StartServer)
|
||||
})
|
||||
}
|
||||
setting.LFS.StartServer = origLFSStartServer
|
||||
}
|
||||
|
||||
func Test_isFeedRequest(t *testing.T) {
|
||||
tests := []struct {
|
||||
want bool
|
||||
path string
|
||||
}{
|
||||
{true, "/user.rss"},
|
||||
{true, "/user/repo.atom"},
|
||||
{false, "/user/repo"},
|
||||
{false, "/use/repo/file.rss"},
|
||||
|
||||
{true, "/org/repo/rss/branch/xxx"},
|
||||
{true, "/org/repo/atom/tag/xxx"},
|
||||
{false, "/org/repo/branch/main/rss/any"},
|
||||
{false, "/org/atom/any"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.path, func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "http://localhost"+tt.path, nil)
|
||||
assert.Equal(t, tt.want, newAuthPathDetector(req).isFeedRequest(req))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -47,9 +47,10 @@ func (b *Basic) Name() string {
|
||||
// name/token on successful validation.
|
||||
// Returns nil if header is empty or validation fails.
|
||||
func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) {
|
||||
// Basic authentication should only fire on API, Download or on Git or LFSPaths
|
||||
// Basic authentication should only fire on API, Feed, Download or on Git or LFSPaths
|
||||
// Not all feed (rss/atom) clients feature the ability to add cookies or headers, so we need to allow basic auth for feeds
|
||||
detector := newAuthPathDetector(req)
|
||||
if !detector.isAPIPath() && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isGitRawOrAttachOrLFSPath() {
|
||||
if !detector.isAPIPath() && !detector.isFeedRequest(req) && !detector.isContainerPath() && !detector.isAttachmentDownload() && !detector.isGitRawOrAttachOrLFSPath() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user