diff --git a/app/commands/feed/import_from_opml.rb b/app/commands/feed/import_from_opml.rb index 16d23faf3..71457f0d2 100644 --- a/app/commands/feed/import_from_opml.rb +++ b/app/commands/feed/import_from_opml.rb @@ -28,8 +28,8 @@ def find_or_create_group(group_name, user) end def create_feed(parsed_feed, group, user) - feed = user.feeds.where(**parsed_feed.slice(:name, :url)) - .first_or_initialize + name = parsed_feed[:name] && ContentSanitizer.call(parsed_feed[:name]) + feed = user.feeds.where(name:, url: parsed_feed[:url]).first_or_initialize find_feed_name(feed, parsed_feed) feed.last_fetched = 1.day.ago if feed.new_record? feed.group_id = group.id if group diff --git a/app/views/stories/_templates.html.erb b/app/views/stories/_templates.html.erb index 5edd72714..741ce4f7e 100644 --- a/app/views/stories/_templates.html.erb +++ b/app/views/stories/_templates.html.erb @@ -5,7 +5,7 @@

- {{= source }} + {{- source }}

diff --git a/spec/commands/feed/import_from_opml_spec.rb b/spec/commands/feed/import_from_opml_spec.rb index d5ab46139..84fe8b0f1 100644 --- a/spec/commands/feed/import_from_opml_spec.rb +++ b/spec/commands/feed/import_from_opml_spec.rb @@ -61,6 +61,21 @@ def find_feed(feed_details) end end + def evil_opml + <<~XML + + + + XML + end + + it "sanitizes feed names" do + described_class.call(evil_opml, user: default_user) + + expect(Feed.last.name).to eq(' Evil') + end + context "adding group_id for existing feeds" do it "retains exising feeds" do feed1 = create_feed(tmw_football) diff --git a/spec/javascript/setup.ts b/spec/javascript/setup.ts index 58ed016d7..9ee9a9e23 100644 --- a/spec/javascript/setup.ts +++ b/spec/javascript/setup.ts @@ -36,7 +36,7 @@ const templateHTML = [ ' ', "
", '

', - " {{= source }}", + " {{- source }}", "

", " ", '
', diff --git a/spec/javascript/spec/views/story_view_spec.ts b/spec/javascript/spec/views/story_view_spec.ts index 0d5c4ec9e..42fb8ecb1 100644 --- a/spec/javascript/spec/views/story_view_spec.ts +++ b/spec/javascript/spec/views/story_view_spec.ts @@ -49,6 +49,16 @@ describe("StoryView", function () { assertPropertyRendered(view.el, story, "source"); }); + it("should escape blog title", function () { + const evilStory = new Story({ ...story.attributes, source: "" }); + const evilView = new StoryView({ model: evilStory }); + evilView.render(); + + const blogTitle = evilView.el.querySelector(".blog-title"); + expect(blogTitle.querySelector("img")).toBeNull(); + expect(blogTitle.textContent.trim()).toBe(""); + }); + it("should render story headline", function () { assertTagExists(view.el, ".story-title"); assertPropertyRendered(view.el, story, "headline");