FIX: allow emoji class when crawling embedded content, add rspc-html-matchers

This commit is contained in:
kerryliu 2015-09-24 15:20:59 -07:00
parent 85daf56ed4
commit b7803fc68e
8 changed files with 103 additions and 2 deletions

View file

@ -120,6 +120,7 @@ group :test, :development do
gem 'simplecov', require: false gem 'simplecov', require: false
gem 'timecop' gem 'timecop'
gem 'rspec-given' gem 'rspec-given'
gem 'rspec-html-matchers'
gem 'pry-nav' gem 'pry-nav'
gem 'spork-rails' gem 'spork-rails'
gem 'byebug', require: ENV['RM_INFO'].nil? gem 'byebug', require: ENV['RM_INFO'].nil?

View file

@ -337,6 +337,9 @@ GEM
rspec-given (3.5.4) rspec-given (3.5.4)
given_core (= 3.5.4) given_core (= 3.5.4)
rspec (>= 2.12) rspec (>= 2.12)
rspec-html-matchers (0.7.0)
nokogiri (~> 1)
rspec (~> 3)
rspec-logsplit (0.1.3) rspec-logsplit (0.1.3)
rspec-mocks (3.2.1) rspec-mocks (3.2.1)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
@ -511,6 +514,7 @@ DEPENDENCIES
rmmseg-cpp rmmseg-cpp
rspec (~> 3.2.0) rspec (~> 3.2.0)
rspec-given rspec-given
rspec-html-matchers
rspec-rails rspec-rails
rtlit rtlit
ruby-readability ruby-readability

View file

@ -53,6 +53,10 @@
{{embedding-setting field="embed_blacklist_selector" {{embedding-setting field="embed_blacklist_selector"
value=embedding.embed_blacklist_selector value=embedding.embed_blacklist_selector
placeholder=".ad-unit, header"}} placeholder=".ad-unit, header"}}
{{embedding-setting field="embed_classname_whitelist"
value=embedding.embed_classname_whitelist
placeholder="emoji, classname"}}
</div> </div>
<div class='embedding-secondary'> <div class='embedding-secondary'>

View file

@ -9,6 +9,7 @@ class Embedding < OpenStruct
embed_truncate embed_truncate
embed_whitelist_selector embed_whitelist_selector
embed_blacklist_selector embed_blacklist_selector
embed_classname_whitelist
feed_polling_enabled feed_polling_enabled
feed_polling_url feed_polling_url
embed_username_key_from_feed) embed_username_key_from_feed)

View file

@ -69,12 +69,13 @@ class TopicEmbed < ActiveRecord::Base
original_uri = URI.parse(url) original_uri = URI.parse(url)
opts = { opts = {
tags: %w[div p code pre h1 h2 h3 b em i strong a img ul li ol blockquote], tags: %w[div p code pre h1 h2 h3 b em i strong a img ul li ol blockquote],
attributes: %w[href src], attributes: %w[href src class],
remove_empty_nodes: false remove_empty_nodes: false
} }
opts[:whitelist] = SiteSetting.embed_whitelist_selector if SiteSetting.embed_whitelist_selector.present? opts[:whitelist] = SiteSetting.embed_whitelist_selector if SiteSetting.embed_whitelist_selector.present?
opts[:blacklist] = SiteSetting.embed_blacklist_selector if SiteSetting.embed_blacklist_selector.present? opts[:blacklist] = SiteSetting.embed_blacklist_selector if SiteSetting.embed_blacklist_selector.present?
embed_classname_whitelist = SiteSetting.embed_classname_whitelist if SiteSetting.embed_classname_whitelist.present?
doc = Readability::Document.new(open(url).read, opts) doc = Readability::Document.new(open(url).read, opts)
@ -96,6 +97,16 @@ class TopicEmbed < ActiveRecord::Base
# If there is a mistyped URL, just do nothing # If there is a mistyped URL, just do nothing
end end
end end
# only allow classes in the whitelist
allowed_classes = if embed_classname_whitelist.blank? then [] else embed_classname_whitelist.split(/[ ,]+/i) end
doc.search('[class]:not([class=""])').each do |node|
classes = node[:class].split(' ').select{ |classname| allowed_classes.include?(classname) }
if classes.length === 0
node.delete('class')
else
node[:class] = classes.join(' ')
end
end
end end
[title, doc.to_html] [title, doc.to_html]

View file

@ -812,6 +812,9 @@ embedding:
embed_blacklist_selector: embed_blacklist_selector:
default: '' default: ''
hidden: true hidden: true
embed_classname_whitelist:
default: 'emoji'
hidden: true
legal: legal:
tos_url: tos_url:

View file

@ -1,4 +1,5 @@
require 'spec_helper' require 'spec_helper'
require 'stringio'
describe TopicEmbed do describe TopicEmbed do
@ -30,7 +31,8 @@ describe TopicEmbed do
expect(post.cooked).to eq(post.raw) expect(post.cooked).to eq(post.raw)
# It converts relative URLs to absolute # It converts relative URLs to absolute
expect(post.cooked.start_with?("hello world new post <a href=\"http://eviltrout.com/hello\">hello</a> <img src=\"http://eviltrout.com/images/wat.jpg\">")).to eq(true) expect(post.cooked).to have_tag('a', with: { href: 'http://eviltrout.com/hello' })
expect(post.cooked).to have_tag('img', with: { src: 'http://eviltrout.com/images/wat.jpg' })
expect(post.topic.has_topic_embed?).to eq(true) expect(post.topic.has_topic_embed?).to eq(true)
expect(TopicEmbed.where(topic_id: post.topic_id)).to be_present expect(TopicEmbed.where(topic_id: post.topic_id)).to be_present
@ -58,4 +60,78 @@ describe TopicEmbed do
end end
describe '.find_remote' do
context 'post with allowed classes "foo" and "emoji"' do
let(:user) { Fabricate(:user) }
let(:url) { 'http://eviltrout.com/123' }
let(:contents) { "my normal size emoji <p class='foo'>Hi</p> <img class='emoji other foo' src='/images/smiley.jpg'>" }
let!(:embeddable_host) { Fabricate(:embeddable_host) }
let!(:file) { StringIO.new }
content = ''
before(:each) do
SiteSetting.stubs(:embed_classname_whitelist).returns 'emoji , foo'
file.stubs(:read).returns contents
TopicEmbed.stubs(:open).returns file
title, content = TopicEmbed.find_remote(url)
end
it 'img node has emoji class' do
expect(content).to have_tag('img', with: { class: 'emoji' })
end
it 'img node has foo class' do
expect(content).to have_tag('img', with: { class: 'foo' })
end
it 'p node has foo class' do
expect(content).to have_tag('p', with: { class: 'foo' })
end
it 'nodes removes classes other than emoji' do
expect(content).to have_tag('img', without: { class: 'other' })
end
end
context 'post with no allowed classes' do
let(:user) { Fabricate(:user) }
let(:url) { 'http://eviltrout.com/123' }
let(:contents) { "my normal size emoji <p class='foo'>Hi</p> <img class='emoji other foo' src='/images/smiley.jpg'>" }
let!(:embeddable_host) { Fabricate(:embeddable_host) }
let!(:file) { StringIO.new }
content = ''
before(:each) do
SiteSetting.stubs(:embed_classname_whitelist).returns ' '
file.stubs(:read).returns contents
TopicEmbed.stubs(:open).returns file
title, content = TopicEmbed.find_remote(url)
end
it 'img node doesn\'t have emoji class' do
expect(content).to have_tag('img', without: { class: 'emoji' })
end
it 'img node doesn\'t have foo class' do
expect(content).to have_tag('img', without: { class: 'foo' })
end
it 'p node doesn\'t foo class' do
expect(content).to have_tag('p', without: { class: 'foo' })
end
it 'img node doesn\'t have other class' do
expect(content).to have_tag('img', without: { class: 'other' })
end
end
end
end end

View file

@ -42,6 +42,7 @@ Spork.prefork do
config.fail_fast = ENV['RSPEC_FAIL_FAST'] == "1" config.fail_fast = ENV['RSPEC_FAIL_FAST'] == "1"
config.include Helpers config.include Helpers
config.include MessageBus config.include MessageBus
config.include RSpecHtmlMatchers
config.mock_framework = :mocha config.mock_framework = :mocha
config.order = 'random' config.order = 'random'
config.infer_spec_type_from_file_location! config.infer_spec_type_from_file_location!