Make image proxy configurable

Adds IMAGE_PROXY configuration setting to change image proxy filter behaviour:

- none = No proxy
- http-only = Proxy only non-HTTPS images (default)
- all = Proxy everything
This commit is contained in:
Dave Z 2018-07-12 20:41:09 -04:00 committed by Frédéric Guillot
parent 6fd6f79daf
commit c926498d3d
4 changed files with 138 additions and 11 deletions

View file

@ -26,6 +26,7 @@ const (
defaultCertDomain = "" defaultCertDomain = ""
defaultCertCache = "/tmp/cert_cache" defaultCertCache = "/tmp/cert_cache"
defaultCleanupFrequency = 24 defaultCleanupFrequency = 24
defaultProxyImages = "http-only"
) )
// Config manages configuration parameters. // Config manages configuration parameters.
@ -217,6 +218,11 @@ func (c *Config) PocketConsumerKey(defaultValue string) string {
return c.get("POCKET_CONSUMER_KEY", defaultValue) return c.get("POCKET_CONSUMER_KEY", defaultValue)
} }
// ProxyImages returns "none" to never proxy, "http-only" to proxy non-HTTPS, "all" to always proxy.
func (c *Config) ProxyImages() string {
return c.get("PROXY_IMAGES", defaultProxyImages)
}
// NewConfig returns a new Config. // NewConfig returns a new Config.
func NewConfig() *Config { func NewConfig() *Config {
cfg := &Config{ cfg := &Config{

View file

@ -8,6 +8,7 @@ import (
"encoding/base64" "encoding/base64"
"strings" "strings"
"github.com/miniflux/miniflux/config"
"github.com/miniflux/miniflux/http/route" "github.com/miniflux/miniflux/http/route"
"github.com/miniflux/miniflux/url" "github.com/miniflux/miniflux/url"
@ -15,8 +16,13 @@ import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
// ImageProxyFilter rewrites image tag URLs without HTTPS to local proxy URL // ImageProxyFilter rewrites image tag URLs to local proxy URL (by default only non-HTTPS URLs)
func ImageProxyFilter(router *mux.Router, data string) string { func ImageProxyFilter(router *mux.Router, cfg *config.Config, data string) string {
proxyImages := cfg.ProxyImages()
if proxyImages == "none" {
return data
}
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data)) doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil { if err != nil {
return data return data
@ -24,7 +30,7 @@ func ImageProxyFilter(router *mux.Router, data string) string {
doc.Find("img").Each(func(i int, img *goquery.Selection) { doc.Find("img").Each(func(i int, img *goquery.Selection) {
if srcAttr, ok := img.Attr("src"); ok { if srcAttr, ok := img.Attr("src"); ok {
if !url.IsHTTPS(srcAttr) { if proxyImages == "all" || !url.IsHTTPS(srcAttr) {
img.SetAttr("src", Proxify(router, srcAttr)) img.SetAttr("src", Proxify(router, srcAttr))
} }
} }

View file

@ -6,17 +6,24 @@ package filter
import ( import (
"net/http" "net/http"
"os"
"testing" "testing"
"github.com/miniflux/miniflux/config"
"github.com/gorilla/mux" "github.com/gorilla/mux"
) )
func TestProxyFilterWithHttp(t *testing.T) { func TestProxyFilterWithHttpDefault(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "http-only")
c := config.NewConfig()
r := mux.NewRouter() r := mux.NewRouter()
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
input := `<p><img src="http://website/folder/image.png" alt="Test"/></p>` input := `<p><img src="http://website/folder/image.png" alt="Test"/></p>`
output := ImageProxyFilter(r, input) output := ImageProxyFilter(r, c, input)
expected := `<p><img src="/proxy/aHR0cDovL3dlYnNpdGUvZm9sZGVyL2ltYWdlLnBuZw==" alt="Test"/></p>` expected := `<p><img src="/proxy/aHR0cDovL3dlYnNpdGUvZm9sZGVyL2ltYWdlLnBuZw==" alt="Test"/></p>`
if expected != output { if expected != output {
@ -24,12 +31,118 @@ func TestProxyFilterWithHttp(t *testing.T) {
} }
} }
func TestProxyFilterWithHttps(t *testing.T) { func TestProxyFilterWithHttpsDefault(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "http-only")
c := config.NewConfig()
r := mux.NewRouter() r := mux.NewRouter()
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
input := `<p><img src="https://website/folder/image.png" alt="Test"/></p>` input := `<p><img src="https://website/folder/image.png" alt="Test"/></p>`
output := ImageProxyFilter(r, input) output := ImageProxyFilter(r, c, input)
expected := `<p><img src="https://website/folder/image.png" alt="Test"/></p>`
if expected != output {
t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected)
}
}
func TestProxyFilterWithHttpNever(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "none")
c := config.NewConfig()
r := mux.NewRouter()
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
input := `<p><img src="http://website/folder/image.png" alt="Test"/></p>`
output := ImageProxyFilter(r, c, input)
expected := input
if expected != output {
t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected)
}
}
func TestProxyFilterWithHttpsNever(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "none")
c := config.NewConfig()
r := mux.NewRouter()
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
input := `<p><img src="https://website/folder/image.png" alt="Test"/></p>`
output := ImageProxyFilter(r, c, input)
expected := input
if expected != output {
t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected)
}
}
func TestProxyFilterWithHttpAlways(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "all")
c := config.NewConfig()
r := mux.NewRouter()
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
input := `<p><img src="http://website/folder/image.png" alt="Test"/></p>`
output := ImageProxyFilter(r, c, input)
expected := `<p><img src="/proxy/aHR0cDovL3dlYnNpdGUvZm9sZGVyL2ltYWdlLnBuZw==" alt="Test"/></p>`
if expected != output {
t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected)
}
}
func TestProxyFilterWithHttpsAlways(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "all")
c := config.NewConfig()
r := mux.NewRouter()
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
input := `<p><img src="https://website/folder/image.png" alt="Test"/></p>`
output := ImageProxyFilter(r, c, input)
expected := `<p><img src="/proxy/aHR0cHM6Ly93ZWJzaXRlL2ZvbGRlci9pbWFnZS5wbmc=" alt="Test"/></p>`
if expected != output {
t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected)
}
}
func TestProxyFilterWithHttpInvalid(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "invalid")
c := config.NewConfig()
r := mux.NewRouter()
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
input := `<p><img src="http://website/folder/image.png" alt="Test"/></p>`
output := ImageProxyFilter(r, c, input)
expected := `<p><img src="/proxy/aHR0cDovL3dlYnNpdGUvZm9sZGVyL2ltYWdlLnBuZw==" alt="Test"/></p>`
if expected != output {
t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected)
}
}
func TestProxyFilterWithHttpsInvalid(t *testing.T) {
os.Clearenv()
os.Setenv("PROXY_IMAGES", "invalid")
c := config.NewConfig()
r := mux.NewRouter()
r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy")
input := `<p><img src="https://website/folder/image.png" alt="Test"/></p>`
output := ImageProxyFilter(r, c, input)
expected := `<p><img src="https://website/folder/image.png" alt="Test"/></p>` expected := `<p><img src="https://website/folder/image.png" alt="Test"/></p>`
if expected != output { if expected != output {

View file

@ -46,14 +46,16 @@ func (f *funcMap) Map() template.FuncMap {
return template.HTML(str) return template.HTML(str)
}, },
"proxyFilter": func(data string) string { "proxyFilter": func(data string) string {
return filter.ImageProxyFilter(f.router, data) return filter.ImageProxyFilter(f.router, f.cfg, data)
}, },
"proxyURL": func(link string) string { "proxyURL": func(link string) string {
if url.IsHTTPS(link) { proxyImages := f.cfg.ProxyImages()
return link
if proxyImages == "all" || (proxyImages != "none" && !url.IsHTTPS(link)) {
return filter.Proxify(f.router, link)
} }
return filter.Proxify(f.router, link) return link
}, },
"domain": func(websiteURL string) string { "domain": func(websiteURL string) string {
return url.Domain(websiteURL) return url.Domain(websiteURL)