feat: server-side feed credentials

If a feed requires credentials, OPDS Proxy can transparently
set them server side by reading the feed configuration.

This is useful in scenarios where the server operator sets up their
own authentication in front of OPDS Proxy and doesn't want to
have users remember separate credentials for each of the configured
feeds.
This commit is contained in:
Evan Buss
2024-07-13 18:23:42 +00:00
parent 28d3a7d761
commit 349e86f0b1
2 changed files with 38 additions and 16 deletions

11
main.go
View File

@@ -26,8 +26,14 @@ type auth struct {
}
type feedConfig struct {
Name string `koanf:"name"`
Url string `koanf:"url"`
Name string `koanf:"name"`
Url string `koanf:"url"`
Username string `koanf:"username"`
Password string `koanf:"password"`
}
func (f feedConfig) HasCredentials() bool {
return f.Username != "" && f.Password != ""
}
var k = koanf.New(".")
@@ -70,7 +76,6 @@ func main() {
config.Auth.HashKey = hashKey
config.Auth.BlockKey = blockKey
}
server, err := NewServer(&config)

View File

@@ -57,7 +57,7 @@ func NewServer(config *config) (*Server, error) {
router := http.NewServeMux()
router.HandleFunc("GET /{$}", handleHome(config.Feeds))
router.HandleFunc("GET /feed", handleFeed("tmp/", s))
router.HandleFunc("GET /feed", handleFeed("tmp/", config.Feeds, s))
router.HandleFunc("/auth", handleAuth(s))
router.Handle("GET /static/", http.FileServer(http.FS(html.StaticFiles())))
@@ -87,7 +87,7 @@ func handleHome(feeds []feedConfig) http.HandlerFunc {
}
}
func handleFeed(outputDir string, s *securecookie.SecureCookie) http.HandlerFunc {
func handleFeed(outputDir string, feeds []feedConfig, s *securecookie.SecureCookie) http.HandlerFunc {
kepubConverter := &convert.KepubConverter{}
mobiConverter := &convert.MobiConverter{}
@@ -110,7 +110,7 @@ func handleFeed(outputDir string, s *securecookie.SecureCookie) http.HandlerFunc
queryURL = replaceSearchPlaceHolder(queryURL, searchTerm)
}
resp, err := fetchFromUrl(queryURL, getCredentials(r, s))
resp, err := fetchFromUrl(queryURL, getCredentials(r, feeds, s))
if err != nil {
handleError(r, w, "Failed to fetch", err)
return
@@ -231,7 +231,33 @@ func handleAuth(s *securecookie.SecureCookie) http.HandlerFunc {
}
}
func getCredentials(r *http.Request, s *securecookie.SecureCookie) *Credentials {
func getCredentials(r *http.Request, feeds []feedConfig, s *securecookie.SecureCookie) *Credentials {
if !r.URL.Query().Has("q") {
return nil
}
feedUrl, err := url.Parse(r.URL.Query().Get("q"))
if err != nil {
return nil
}
// Try to get credentials from the config first
for _, feed := range feeds {
if !feed.HasCredentials() {
continue
}
configUrl, err := url.Parse(feed.Url)
if err != nil {
continue
}
if configUrl.Hostname() == feedUrl.Hostname() {
return &Credentials{Username: feed.Username, Password: feed.Password}
}
}
// Otherwise, try to get credentials from the cookie
cookie, err := r.Cookie("auth-creds")
if err != nil {
return nil
@@ -242,15 +268,6 @@ func getCredentials(r *http.Request, s *securecookie.SecureCookie) *Credentials
return nil
}
if !r.URL.Query().Has("q") {
return nil
}
feedUrl, err := url.Parse(r.URL.Query().Get("q"))
if err != nil {
return nil
}
return value[feedUrl.Hostname()]
}