1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-09-15 18:57:04 +00:00

refactor(sanitizer): use a map for iframe allow list

This commit is contained in:
Frédéric Guillot 2025-06-13 20:44:47 -07:00
parent 44c48d109f
commit ac44507af2
5 changed files with 119 additions and 40 deletions

View file

@ -110,6 +110,21 @@ var (
"munderover": {},
"semantics": {},
}
iframeAllowList = map[string]struct{}{
"bandcamp.com": {},
"cdn.embedly.com": {},
"dailymotion.com": {},
"open.spotify.com": {},
"player.bilibili.com": {},
"player.twitch.tv": {},
"player.vimeo.com": {},
"soundcloud.com": {},
"vk.com": {},
"w.soundcloud.com": {},
"youtube-nocookie.com": {},
"youtube.com": {},
}
)
type SanitizerOptions struct {
@ -266,7 +281,7 @@ func sanitizeAttributes(parsedBaseUrl *url.URL, baseURL, tagName string, attribu
if isExternalResourceAttribute(attribute.Key) {
switch {
case tagName == "iframe":
if !isValidIframeSource(parsedBaseUrl, baseURL, attribute.Val) {
if !isValidIframeSource(attribute.Val) {
continue
}
value = rewriteIframeURL(attribute.Val)
@ -448,39 +463,22 @@ func isBlockedResource(src string) bool {
})
}
func isValidIframeSource(parsedBaseUrl *url.URL, baseURL, src string) bool {
whitelist := []string{
"bandcamp.com",
"cdn.embedly.com",
"player.bilibili.com",
"player.twitch.tv",
"player.vimeo.com",
"soundcloud.com",
"vk.com",
"w.soundcloud.com",
"dailymotion.com",
"youtube-nocookie.com",
"youtube.com",
"open.spotify.com",
}
domain := urllib.Domain(src)
func isValidIframeSource(iframeSourceURL string) bool {
iframeSourceDomain := strings.TrimPrefix(urllib.Domain(iframeSourceURL), "www.")
baseDomain := baseURL
if parsedBaseUrl != nil {
baseDomain = parsedBaseUrl.Hostname()
}
// allow iframe from same origin
if baseDomain == domain {
if _, ok := iframeAllowList[iframeSourceDomain]; ok {
return true
}
// allow iframe from custom invidious instance
if config.Opts.InvidiousInstance() == domain {
if ytDomain := config.Opts.YouTubeEmbedDomain(); ytDomain != "" && iframeSourceDomain == strings.TrimPrefix(ytDomain, "www.") {
return true
}
return slices.Contains(whitelist, strings.TrimPrefix(domain, "www."))
if invidiousInstance := config.Opts.InvidiousInstance(); invidiousInstance != "" && iframeSourceDomain == strings.TrimPrefix(invidiousInstance, "www.") {
return true
}
return false
}
func rewriteIframeURL(link string) string {

View file

@ -13,12 +13,6 @@ import (
"miniflux.app/v2/internal/config"
)
func TestMain(m *testing.M) {
config.Opts = config.NewOptions()
exitCode := m.Run()
os.Exit(exitCode)
}
func BenchmarkSanitize(b *testing.B) {
var testCases = map[string][]string{
"miniflux_github.html": {"https://github.com/miniflux/v2", ""},
@ -352,6 +346,8 @@ func TestInvalidNestedTag(t *testing.T) {
}
func TestInvalidIFrame(t *testing.T) {
config.Opts = config.NewOptions()
input := `<iframe src="http://example.org/"></iframe>`
expected := ``
output := SanitizeHTMLWithDefaultOptions("http://example.com/", input)
@ -361,7 +357,51 @@ func TestInvalidIFrame(t *testing.T) {
}
}
func TestSameDomainIFrame(t *testing.T) {
config.Opts = config.NewOptions()
input := `<iframe src="http://example.com/test"></iframe>`
expected := ``
output := SanitizeHTMLWithDefaultOptions("http://example.com/", input)
if expected != output {
t.Errorf(`Wrong output: %q != %q`, expected, output)
}
}
func TestInvidiousIFrame(t *testing.T) {
config.Opts = config.NewOptions()
input := `<iframe src="https://yewtu.be/watch?v=video_id"></iframe>`
expected := `<iframe src="https://yewtu.be/watch?v=video_id" sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox" loading="lazy"></iframe>`
output := SanitizeHTMLWithDefaultOptions("http://example.com/", input)
if expected != output {
t.Errorf(`Wrong output: %q != %q`, expected, output)
}
}
func TestCustomYoutubeEmbedURL(t *testing.T) {
os.Setenv("YOUTUBE_EMBED_URL_OVERRIDE", "https://www.invidious.custom/embed/")
defer os.Clearenv()
var err error
if config.Opts, err = config.NewParser().ParseEnvironmentVariables(); err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}
input := `<iframe src="https://www.invidious.custom/embed/1234"></iframe>`
expected := `<iframe src="https://www.invidious.custom/embed/1234" sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox" loading="lazy"></iframe>`
output := SanitizeHTMLWithDefaultOptions("http://example.com/", input)
if expected != output {
t.Errorf(`Wrong output: %q != %q`, expected, output)
}
}
func TestIFrameWithChildElements(t *testing.T) {
config.Opts = config.NewOptions()
input := `<iframe src="https://www.youtube.com/"><p>test</p></iframe>`
expected := `<iframe src="https://www.youtube.com/" sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox" loading="lazy"></iframe>`
output := SanitizeHTMLWithDefaultOptions("http://example.com/", input)
@ -750,13 +790,11 @@ func TestReplaceProtocolRelativeYoutubeURL(t *testing.T) {
}
func TestReplaceYoutubeURLWithCustomURL(t *testing.T) {
os.Clearenv()
defer os.Clearenv()
os.Setenv("YOUTUBE_EMBED_URL_OVERRIDE", "https://invidious.custom/embed/")
var err error
parser := config.NewParser()
config.Opts, err = parser.ParseEnvironmentVariables()
config.Opts, err = config.NewParser().ParseEnvironmentVariables()
if err != nil {
t.Fatalf(`Parsing failure: %v`, err)
}