From 3e802f1c87b4824b47f2d3015ef02b846cb33a20 Mon Sep 17 00:00:00 2001 From: SouthFox Date: Tue, 23 Jul 2024 16:08:18 +0800 Subject: [PATCH] feat: referer spoof Signed-off-by: SouthFox --- internal/api/entry.go | 4 ++-- internal/mediaproxy/rewriter.go | 12 ++++++++---- internal/mediaproxy/url.go | 12 +++++++++--- internal/template/functions.go | 4 ++-- internal/template/templates/views/entry.html | 2 +- internal/ui/proxy.go | 7 +++++++ internal/ui/ui.go | 1 + 7 files changed, 30 insertions(+), 12 deletions(-) diff --git a/internal/api/entry.go b/internal/api/entry.go index 6a299a01..04687c2f 100644 --- a/internal/api/entry.go +++ b/internal/api/entry.go @@ -36,7 +36,7 @@ func (h *handler) getEntryFromBuilder(w http.ResponseWriter, r *http.Request, b return } - entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, r.Host, entry.Content) + entry.Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, r.Host, entry.Content, entry.Feed.SiteURL) proxyOption := config.Opts.MediaProxyMode() for i := range entry.Enclosures { @@ -164,7 +164,7 @@ func (h *handler) findEntries(w http.ResponseWriter, r *http.Request, feedID int } for i := range entries { - entries[i].Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, r.Host, entries[i].Content) + entries[i].Content = mediaproxy.RewriteDocumentWithAbsoluteProxyURL(h.router, r.Host, entries[i].Content, entries[i].Feed.SiteURL) } json.OK(w, r, &entriesResponse{Total: count, Entries: entries}) diff --git a/internal/mediaproxy/rewriter.go b/internal/mediaproxy/rewriter.go index b77be654..856cb85c 100644 --- a/internal/mediaproxy/rewriter.go +++ b/internal/mediaproxy/rewriter.go @@ -16,13 +16,17 @@ import ( type urlProxyRewriter func(router *mux.Router, url string) string -func RewriteDocumentWithRelativeProxyURL(router *mux.Router, htmlDocument string) string { - return genericProxyRewriter(router, ProxifyRelativeURL, htmlDocument) +func RewriteDocumentWithRelativeProxyURL(router *mux.Router, htmlDocument string, feedSiteURL ...string) string { + proxifyFunction := func(router *mux.Router, mediaURL string) string { + return ProxifyRelativeURL(router, mediaURL, feedSiteURL...) + } + + return genericProxyRewriter(router, proxifyFunction, htmlDocument) } -func RewriteDocumentWithAbsoluteProxyURL(router *mux.Router, host, htmlDocument string) string { +func RewriteDocumentWithAbsoluteProxyURL(router *mux.Router, host, htmlDocument string, feedSiteURL ...string) string { proxifyFunction := func(router *mux.Router, url string) string { - return ProxifyAbsoluteURL(router, host, url) + return ProxifyAbsoluteURL(router, host, url, feedSiteURL...) } return genericProxyRewriter(router, proxifyFunction, htmlDocument) } diff --git a/internal/mediaproxy/url.go b/internal/mediaproxy/url.go index c3a9a953..bd31cd17 100644 --- a/internal/mediaproxy/url.go +++ b/internal/mediaproxy/url.go @@ -18,7 +18,7 @@ import ( "miniflux.app/v2/internal/config" ) -func ProxifyRelativeURL(router *mux.Router, mediaURL string) string { +func ProxifyRelativeURL(router *mux.Router, mediaURL string, feedSiteURL ...string) string { if mediaURL == "" { return "" } @@ -30,10 +30,16 @@ func ProxifyRelativeURL(router *mux.Router, mediaURL string) string { mac := hmac.New(sha256.New, config.Opts.MediaProxyPrivateKey()) mac.Write([]byte(mediaURL)) digest := mac.Sum(nil) + + if len(feedSiteURL) > 0 { + referer := feedSiteURL[0] + return route.Path(router, "proxyWithReferer", "encodedDigest", base64.URLEncoding.EncodeToString(digest), "encodedURL", base64.URLEncoding.EncodeToString([]byte(mediaURL)), "encodedReferer", base64.URLEncoding.EncodeToString([]byte(referer))) + } + return route.Path(router, "proxy", "encodedDigest", base64.URLEncoding.EncodeToString(digest), "encodedURL", base64.URLEncoding.EncodeToString([]byte(mediaURL))) } -func ProxifyAbsoluteURL(router *mux.Router, host, mediaURL string) string { +func ProxifyAbsoluteURL(router *mux.Router, host, mediaURL string, feedSiteURL ...string) string { if mediaURL == "" { return "" } @@ -42,7 +48,7 @@ func ProxifyAbsoluteURL(router *mux.Router, host, mediaURL string) string { return proxifyURLWithCustomProxy(mediaURL, customProxyURL) } - proxifiedUrl := ProxifyRelativeURL(router, mediaURL) + proxifiedUrl := ProxifyRelativeURL(router, mediaURL, feedSiteURL...) scheme := "http" if config.Opts.HTTPS { scheme = "https" diff --git a/internal/template/functions.go b/internal/template/functions.go index cfbfc53d..9c1018e9 100644 --- a/internal/template/functions.go +++ b/internal/template/functions.go @@ -57,8 +57,8 @@ func (f *funcMap) Map() template.FuncMap { "noescape": func(str string) template.HTML { return template.HTML(str) }, - "proxyFilter": func(data string) string { - return mediaproxy.RewriteDocumentWithRelativeProxyURL(f.router, data) + "proxyFilter": func(data string, feedSiteURL ...string) string { + return mediaproxy.RewriteDocumentWithRelativeProxyURL(f.router, data, feedSiteURL...) }, "proxyURL": func(link string) string { mediaProxyMode := config.Opts.MediaProxyMode() diff --git a/internal/template/templates/views/entry.html b/internal/template/templates/views/entry.html index 85618954..037bec3b 100644 --- a/internal/template/templates/views/entry.html +++ b/internal/template/templates/views/entry.html @@ -205,7 +205,7 @@ {{ end }} {{end}} {{ if .user }} - {{ noescape (proxyFilter .entry.Content) }} + {{ noescape (proxyFilter .entry.Content .entry.Feed.SiteURL) }} {{ else }} {{ noescape .entry.Content }} {{ end }} diff --git a/internal/ui/proxy.go b/internal/ui/proxy.go index 34965275..311b3f53 100644 --- a/internal/ui/proxy.go +++ b/internal/ui/proxy.go @@ -29,6 +29,7 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) { encodedDigest := request.RouteStringParam(r, "encodedDigest") encodedURL := request.RouteStringParam(r, "encodedURL") + encodedReferer := request.RouteStringParam(r, "encodedReferer") if encodedURL == "" { html.BadRequest(w, r, errors.New("no URL provided")) return @@ -46,6 +47,8 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) { return } + decodeReferer, _ := base64.URLEncoding.DecodeString(encodedReferer) + mac := hmac.New(sha256.New, config.Opts.MediaProxyPrivateKey()) mac.Write(decodedURL) expectedMAC := mac.Sum(nil) @@ -87,6 +90,10 @@ func (h *handler) mediaProxy(w http.ResponseWriter, r *http.Request) { return } + if decodeReferer != nil { + req.Header.Add("Referer", string(decodeReferer)) + } + // Note: User-Agent HTTP header is omitted to avoid being blocked by bot protection mechanisms. req.Header.Add("Connection", "close") diff --git a/internal/ui/ui.go b/internal/ui/ui.go index d6641c01..2f55f7d7 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -103,6 +103,7 @@ func Serve(router *mux.Router, store *storage.Storage, pool *worker.Pool) { uiRouter.HandleFunc("/entry/enclosure/{enclosureID}/save-progression", handler.saveEnclosureProgression).Name("saveEnclosureProgression").Methods(http.MethodPost) uiRouter.HandleFunc("/entry/download/{entryID}", handler.fetchContent).Name("fetchContent").Methods(http.MethodPost) uiRouter.HandleFunc("/proxy/{encodedDigest}/{encodedURL}", handler.mediaProxy).Name("proxy").Methods(http.MethodGet) + uiRouter.HandleFunc("/proxy/{encodedDigest}/{encodedURL}/{encodedReferer}", handler.mediaProxy).Name("proxyWithReferer").Methods(http.MethodGet) uiRouter.HandleFunc("/entry/bookmark/{entryID}", handler.toggleBookmark).Name("toggleBookmark").Methods(http.MethodPost) // Share pages.