From bbc087d2ad53d201aed4e121e8c443def124e3f8 Mon Sep 17 00:00:00 2001 From: Nicole <76132106+nicolecomputer@users.noreply.github.com> Date: Mon, 29 Aug 2022 21:33:47 -0600 Subject: [PATCH] Allow setting a custom image proxy URL --- config/options.go | 9 +++++++++ config/parser.go | 2 ++ miniflux.1 | 5 +++++ proxy/image_proxy_test.go | 24 ++++++++++++++++++++++++ proxy/proxy.go | 18 +++++++++++++++++- 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/config/options.go b/config/options.go index bd2bd6b5..4af429f1 100644 --- a/config/options.go +++ b/config/options.go @@ -46,6 +46,7 @@ const ( defaultCleanupArchiveBatchSize = 10000 defaultCleanupRemoveSessionsDays = 30 defaultProxyImages = "http-only" + defaultProxyImageUrl = "" defaultFetchYouTubeWatchTime = false defaultCreateAdmin = false defaultAdminUsername = "" @@ -116,6 +117,7 @@ type Options struct { adminUsername string adminPassword string proxyImages string + proxyImageUrl string fetchYouTubeWatchTime bool oauth2UserCreationAllowed bool oauth2ClientID string @@ -175,6 +177,7 @@ func NewOptions() *Options { workerPoolSize: defaultWorkerPoolSize, createAdmin: defaultCreateAdmin, proxyImages: defaultProxyImages, + proxyImageUrl: defaultProxyImageUrl, fetchYouTubeWatchTime: defaultFetchYouTubeWatchTime, oauth2UserCreationAllowed: defaultOAuth2UserCreation, oauth2ClientID: defaultOAuth2ClientID, @@ -410,6 +413,11 @@ func (o *Options) ProxyImages() string { return o.proxyImages } +// ProxyImageUrl returns a string of a URL to use to proxy image requests +func (o *Options) ProxyImageUrl() string { + return o.proxyImageUrl +} + // HasHTTPService returns true if the HTTP service is enabled. func (o *Options) HasHTTPService() bool { return o.httpService @@ -543,6 +551,7 @@ func (o *Options) SortedOptions(redactSecret bool) []*Option { "POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit, "POLLING_SCHEDULER": o.pollingScheduler, "PROXY_IMAGES": o.proxyImages, + "PROXY_IMAGE_URL": o.proxyImageUrl, "ROOT_URL": o.rootURL, "RUN_MIGRATIONS": o.runMigrations, "SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL": o.schedulerEntryFrequencyMaxInterval, diff --git a/config/parser.go b/config/parser.go index 2d4f5727..310e9323 100644 --- a/config/parser.go +++ b/config/parser.go @@ -139,6 +139,8 @@ func (p *Parser) parseLines(lines []string) (err error) { p.opts.pollingParsingErrorLimit = parseInt(value, defaultPollingParsingErrorLimit) case "PROXY_IMAGES": p.opts.proxyImages = parseString(value, defaultProxyImages) + case "PROXY_IMAGE_URL": + p.opts.proxyImageUrl = parseString(value, defaultProxyImageUrl) case "CREATE_ADMIN": p.opts.createAdmin = parseBool(value, defaultCreateAdmin) case "ADMIN_USERNAME": diff --git a/miniflux.1 b/miniflux.1 index 4af55582..330250b1 100644 --- a/miniflux.1 +++ b/miniflux.1 @@ -370,6 +370,11 @@ Avoids mixed content warnings for external images: http-only, all, or none\&. .br Default is http-only\&. .TP +.B PROXY_IMAGE_URL +Sets a server to proxy images through\&. +.br +Default is empty, miniflux does the proxying\&. +.TP .B HTTP_CLIENT_TIMEOUT Time limit in seconds before the HTTP client cancel the request\&. .br diff --git a/proxy/image_proxy_test.go b/proxy/image_proxy_test.go index b3c6920f..2e0a9513 100644 --- a/proxy/image_proxy_test.go +++ b/proxy/image_proxy_test.go @@ -151,6 +151,30 @@ func TestProxyFilterWithHttpsAlways(t *testing.T) { } } +func TestProxyFilterWithHttpsAlwaysAndCustomProxyServer(t *testing.T) { + os.Clearenv() + os.Setenv("PROXY_IMAGES", "all") + os.Setenv("PROXY_IMAGE_URL", "https://proxy-example/proxy") + + var err error + parser := config.NewParser() + config.Opts, err = parser.ParseEnvironmentVariables() + if err != nil { + t.Fatalf(`Parsing failure: %v`, err) + } + + r := mux.NewRouter() + r.HandleFunc("/proxy/{encodedURL}", func(w http.ResponseWriter, r *http.Request) {}).Name("proxy") + + input := `
` + output := ImageProxyRewriter(r, 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") diff --git a/proxy/proxy.go b/proxy/proxy.go index ad694233..312891b4 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -6,16 +6,32 @@ package proxy // import "miniflux.app/proxy" import ( "encoding/base64" + "net/url" + "path" "miniflux.app/http/route" "github.com/gorilla/mux" + + "miniflux.app/config" ) // ProxifyURL generates an URL for a proxified resource. func ProxifyURL(router *mux.Router, link string) string { if link != "" { - return route.Path(router, "proxy", "encodedURL", base64.URLEncoding.EncodeToString([]byte(link))) + proxyImageUrl := config.Opts.ProxyImageUrl() + + if proxyImageUrl == "" { + return route.Path(router, "proxy", "encodedURL", base64.URLEncoding.EncodeToString([]byte(link))) + } + + proxyUrl, err := url.Parse(proxyImageUrl) + if err != nil { + return "" + } + + proxyUrl.Path = path.Join(proxyUrl.Path, base64.URLEncoding.EncodeToString([]byte(link))) + return proxyUrl.String() } return "" }