Allow setting a custom image proxy URL
This commit is contained in:
parent
b8c3153b75
commit
bbc087d2ad
5 changed files with 57 additions and 1 deletions
|
@ -46,6 +46,7 @@ const (
|
||||||
defaultCleanupArchiveBatchSize = 10000
|
defaultCleanupArchiveBatchSize = 10000
|
||||||
defaultCleanupRemoveSessionsDays = 30
|
defaultCleanupRemoveSessionsDays = 30
|
||||||
defaultProxyImages = "http-only"
|
defaultProxyImages = "http-only"
|
||||||
|
defaultProxyImageUrl = ""
|
||||||
defaultFetchYouTubeWatchTime = false
|
defaultFetchYouTubeWatchTime = false
|
||||||
defaultCreateAdmin = false
|
defaultCreateAdmin = false
|
||||||
defaultAdminUsername = ""
|
defaultAdminUsername = ""
|
||||||
|
@ -116,6 +117,7 @@ type Options struct {
|
||||||
adminUsername string
|
adminUsername string
|
||||||
adminPassword string
|
adminPassword string
|
||||||
proxyImages string
|
proxyImages string
|
||||||
|
proxyImageUrl string
|
||||||
fetchYouTubeWatchTime bool
|
fetchYouTubeWatchTime bool
|
||||||
oauth2UserCreationAllowed bool
|
oauth2UserCreationAllowed bool
|
||||||
oauth2ClientID string
|
oauth2ClientID string
|
||||||
|
@ -175,6 +177,7 @@ func NewOptions() *Options {
|
||||||
workerPoolSize: defaultWorkerPoolSize,
|
workerPoolSize: defaultWorkerPoolSize,
|
||||||
createAdmin: defaultCreateAdmin,
|
createAdmin: defaultCreateAdmin,
|
||||||
proxyImages: defaultProxyImages,
|
proxyImages: defaultProxyImages,
|
||||||
|
proxyImageUrl: defaultProxyImageUrl,
|
||||||
fetchYouTubeWatchTime: defaultFetchYouTubeWatchTime,
|
fetchYouTubeWatchTime: defaultFetchYouTubeWatchTime,
|
||||||
oauth2UserCreationAllowed: defaultOAuth2UserCreation,
|
oauth2UserCreationAllowed: defaultOAuth2UserCreation,
|
||||||
oauth2ClientID: defaultOAuth2ClientID,
|
oauth2ClientID: defaultOAuth2ClientID,
|
||||||
|
@ -410,6 +413,11 @@ func (o *Options) ProxyImages() string {
|
||||||
return o.proxyImages
|
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.
|
// HasHTTPService returns true if the HTTP service is enabled.
|
||||||
func (o *Options) HasHTTPService() bool {
|
func (o *Options) HasHTTPService() bool {
|
||||||
return o.httpService
|
return o.httpService
|
||||||
|
@ -543,6 +551,7 @@ func (o *Options) SortedOptions(redactSecret bool) []*Option {
|
||||||
"POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit,
|
"POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit,
|
||||||
"POLLING_SCHEDULER": o.pollingScheduler,
|
"POLLING_SCHEDULER": o.pollingScheduler,
|
||||||
"PROXY_IMAGES": o.proxyImages,
|
"PROXY_IMAGES": o.proxyImages,
|
||||||
|
"PROXY_IMAGE_URL": o.proxyImageUrl,
|
||||||
"ROOT_URL": o.rootURL,
|
"ROOT_URL": o.rootURL,
|
||||||
"RUN_MIGRATIONS": o.runMigrations,
|
"RUN_MIGRATIONS": o.runMigrations,
|
||||||
"SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL": o.schedulerEntryFrequencyMaxInterval,
|
"SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL": o.schedulerEntryFrequencyMaxInterval,
|
||||||
|
|
|
@ -139,6 +139,8 @@ func (p *Parser) parseLines(lines []string) (err error) {
|
||||||
p.opts.pollingParsingErrorLimit = parseInt(value, defaultPollingParsingErrorLimit)
|
p.opts.pollingParsingErrorLimit = parseInt(value, defaultPollingParsingErrorLimit)
|
||||||
case "PROXY_IMAGES":
|
case "PROXY_IMAGES":
|
||||||
p.opts.proxyImages = parseString(value, defaultProxyImages)
|
p.opts.proxyImages = parseString(value, defaultProxyImages)
|
||||||
|
case "PROXY_IMAGE_URL":
|
||||||
|
p.opts.proxyImageUrl = parseString(value, defaultProxyImageUrl)
|
||||||
case "CREATE_ADMIN":
|
case "CREATE_ADMIN":
|
||||||
p.opts.createAdmin = parseBool(value, defaultCreateAdmin)
|
p.opts.createAdmin = parseBool(value, defaultCreateAdmin)
|
||||||
case "ADMIN_USERNAME":
|
case "ADMIN_USERNAME":
|
||||||
|
|
|
@ -370,6 +370,11 @@ Avoids mixed content warnings for external images: http-only, all, or none\&.
|
||||||
.br
|
.br
|
||||||
Default is http-only\&.
|
Default is http-only\&.
|
||||||
.TP
|
.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
|
.B HTTP_CLIENT_TIMEOUT
|
||||||
Time limit in seconds before the HTTP client cancel the request\&.
|
Time limit in seconds before the HTTP client cancel the request\&.
|
||||||
.br
|
.br
|
||||||
|
|
|
@ -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 := `<p><img src="https://website/folder/image.png" alt="Test"/></p>`
|
||||||
|
output := ImageProxyRewriter(r, input)
|
||||||
|
expected := `<p><img src="https://proxy-example/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) {
|
func TestProxyFilterWithHttpInvalid(t *testing.T) {
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("PROXY_IMAGES", "invalid")
|
os.Setenv("PROXY_IMAGES", "invalid")
|
||||||
|
|
|
@ -6,16 +6,32 @@ package proxy // import "miniflux.app/proxy"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
|
||||||
"miniflux.app/http/route"
|
"miniflux.app/http/route"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
|
"miniflux.app/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProxifyURL generates an URL for a proxified resource.
|
// ProxifyURL generates an URL for a proxified resource.
|
||||||
func ProxifyURL(router *mux.Router, link string) string {
|
func ProxifyURL(router *mux.Router, link string) string {
|
||||||
if link != "" {
|
if link != "" {
|
||||||
|
proxyImageUrl := config.Opts.ProxyImageUrl()
|
||||||
|
|
||||||
|
if proxyImageUrl == "" {
|
||||||
return route.Path(router, "proxy", "encodedURL", base64.URLEncoding.EncodeToString([]byte(link)))
|
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 ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue