diff --git a/filter/doc.go b/filter/doc.go deleted file mode 100644 index 4028feca..00000000 --- a/filter/doc.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2018 Frédéric Guillot. All rights reserved. -// Use of this source code is governed by the Apache 2.0 -// license that can be found in the LICENSE file. - -/* - -Package filter implements a content filter to rewrite image links. - -*/ -package filter // import "miniflux.app/filter" diff --git a/filter/image_proxy_filter.go b/filter/image_proxy_filter.go deleted file mode 100644 index 01ae5917..00000000 --- a/filter/image_proxy_filter.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017 Frédéric Guillot. All rights reserved. -// Use of this source code is governed by the Apache 2.0 -// license that can be found in the LICENSE file. - -package filter // import "miniflux.app/filter" - -import ( - "encoding/base64" - "strings" - - "miniflux.app/config" - "miniflux.app/http/route" - "miniflux.app/url" - - "github.com/PuerkitoBio/goquery" - "github.com/gorilla/mux" -) - -// ImageProxyFilter rewrites image tag URLs to local proxy URL (by default only non-HTTPS URLs) -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)) - if err != nil { - return data - } - - doc.Find("img").Each(func(i int, img *goquery.Selection) { - if srcAttr, ok := img.Attr("src"); ok { - if proxyImages == "all" || !url.IsHTTPS(srcAttr) { - img.SetAttr("src", Proxify(router, srcAttr)) - } - } - }) - - output, _ := doc.Find("body").First().Html() - return output -} - -// Proxify returns a proxified link. -func Proxify(router *mux.Router, link string) string { - // We use base64 url encoding to avoid slash in the URL. - return route.Path(router, "proxy", "encodedURL", base64.URLEncoding.EncodeToString([]byte(link))) -} diff --git a/filter/image_proxy_filter_test.go b/filter/image_proxy_filter_test.go deleted file mode 100644 index 8e97cd00..00000000 --- a/filter/image_proxy_filter_test.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2017 Frédéric Guillot. All rights reserved. -// Use of this source code is governed by the Apache 2.0 -// license that can be found in the LICENSE file. - -package filter // import "miniflux.app/filter" - -import ( - "net/http" - "os" - "testing" - - "miniflux.app/config" - - "github.com/gorilla/mux" -) - -func TestProxyFilterWithHttpDefault(t *testing.T) { - os.Clearenv() - os.Setenv("PROXY_IMAGES", "http-only") - c := config.NewConfig() - - r := mux.NewRouter() - r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") - - input := `
` - output := ImageProxyFilter(r, c, input) - expected := `` - - if expected != output { - t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected) - } -} - -func TestProxyFilterWithHttpsDefault(t *testing.T) { - os.Clearenv() - os.Setenv("PROXY_IMAGES", "http-only") - c := config.NewConfig() - - r := mux.NewRouter() - r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") - - input := `` - output := ImageProxyFilter(r, c, input) - expected := `` - - 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 := `` - 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 := `` - 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 := `` - output := ImageProxyFilter(r, c, input) - expected := `` - - 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 := `` - output := ImageProxyFilter(r, c, input) - expected := `` - - 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 := `` - output := ImageProxyFilter(r, c, input) - expected := `` - - 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 := `` - output := ImageProxyFilter(r, c, input) - expected := `` - - if expected != output { - t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected) - } -} diff --git a/reader/processor/filter.go b/reader/processor/processor.go similarity index 100% rename from reader/processor/filter.go rename to reader/processor/processor.go diff --git a/template/functions.go b/template/functions.go index 84a02f44..d99f2379 100644 --- a/template/functions.go +++ b/template/functions.go @@ -5,6 +5,7 @@ package template // import "miniflux.app/template" import ( + "encoding/base64" "fmt" "math" "html/template" @@ -12,14 +13,15 @@ import ( "strings" "time" - "github.com/gorilla/mux" "miniflux.app/config" - "miniflux.app/filter" "miniflux.app/http/route" "miniflux.app/locale" "miniflux.app/model" "miniflux.app/timezone" "miniflux.app/url" + + "github.com/gorilla/mux" + "github.com/PuerkitoBio/goquery" ) type funcMap struct { @@ -50,13 +52,13 @@ func (f *funcMap) Map() template.FuncMap { return template.HTML(str) }, "proxyFilter": func(data string) string { - return filter.ImageProxyFilter(f.router, f.cfg, data) + return imageProxyFilter(f.router, f.cfg, data) }, "proxyURL": func(link string) string { proxyImages := f.cfg.ProxyImages() if proxyImages == "all" || (proxyImages != "none" && !url.IsHTTPS(link)) { - return filter.Proxify(f.router, link) + return proxify(f.router, link) } return link @@ -175,3 +177,31 @@ func elapsedTime(printer *locale.Printer, tz string, t time.Time) string { return printer.Plural("time_elapsed.years", years, years) } } + +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)) + if err != nil { + return data + } + + doc.Find("img").Each(func(i int, img *goquery.Selection) { + if srcAttr, ok := img.Attr("src"); ok { + if proxyImages == "all" || !url.IsHTTPS(srcAttr) { + img.SetAttr("src", proxify(router, srcAttr)) + } + } + }) + + output, _ := doc.Find("body").First().Html() + return output +} + +func proxify(router *mux.Router, link string) string { + // We use base64 url encoding to avoid slash in the URL. + return route.Path(router, "proxy", "encodedURL", base64.URLEncoding.EncodeToString([]byte(link))) +} diff --git a/template/functions_test.go b/template/functions_test.go index 1bfb919a..a816eb77 100644 --- a/template/functions_test.go +++ b/template/functions_test.go @@ -5,10 +5,15 @@ package template // import "miniflux.app/template" import ( + "net/http" + "os" "testing" "time" + "miniflux.app/config" "miniflux.app/locale" + + "github.com/gorilla/mux" ) func TestDict(t *testing.T) { @@ -125,3 +130,139 @@ func TestElapsedTime(t *testing.T) { } } } + +func TestProxyFilterWithHttpDefault(t *testing.T) { + os.Clearenv() + os.Setenv("PROXY_IMAGES", "http-only") + c := config.NewConfig() + + r := mux.NewRouter() + r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") + + input := `` + output := imageProxyFilter(r, c, input) + expected := `` + + if expected != output { + t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected) + } +} + +func TestProxyFilterWithHttpsDefault(t *testing.T) { + os.Clearenv() + os.Setenv("PROXY_IMAGES", "http-only") + c := config.NewConfig() + + r := mux.NewRouter() + r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") + + input := `` + output := imageProxyFilter(r, c, input) + expected := `` + + 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 := `` + 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 := `` + 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 := `` + output := imageProxyFilter(r, c, input) + expected := `` + + 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 := `` + output := imageProxyFilter(r, c, input) + expected := `` + + 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 := `` + output := imageProxyFilter(r, c, input) + expected := `` + + 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 := `` + output := imageProxyFilter(r, c, input) + expected := `` + + if expected != output { + t.Errorf(`Not expected output: got "%s" instead of "%s"`, output, expected) + } +}