diff --git a/app/assets/javascripts/admin/components/embeddable-host.js.es6 b/app/assets/javascripts/admin/components/embeddable-host.js.es6
index f33c75096..2a5d7c030 100644
--- a/app/assets/javascripts/admin/components/embeddable-host.js.es6
+++ b/app/assets/javascripts/admin/components/embeddable-host.js.es6
@@ -30,10 +30,11 @@ export default Ember.Component.extend(bufferedProperty('host'), {
save() {
if (this.get('cantSave')) { return; }
- const props = this.get('buffered').getProperties('host');
+ const props = this.get('buffered').getProperties('host', 'path_whitelist');
props.category_id = this.get('categoryId');
const host = this.get('host');
+
host.save(props).then(() => {
host.set('category', Discourse.Category.findById(this.get('categoryId')));
this.set('editToggled', false);
diff --git a/app/assets/javascripts/admin/templates/components/embeddable-host.hbs b/app/assets/javascripts/admin/templates/components/embeddable-host.hbs
index c35d40e1d..5f2581138 100644
--- a/app/assets/javascripts/admin/templates/components/embeddable-host.hbs
+++ b/app/assets/javascripts/admin/templates/components/embeddable-host.hbs
@@ -2,6 +2,9 @@
{{input value=buffered.host placeholder="example.com" enter="save" class="host-name"}}
|
+
+ {{input value=buffered.path_whitelist placeholder="/blog/.*" enter="save" class="path-whitelist"}}
+ |
{{category-chooser value=categoryId}}
|
@@ -11,6 +14,7 @@
{{else}}
{{host.host}} |
+ {{host.path_whitelist}} |
{{category-badge host.category}} |
{{d-button icon="pencil" action="edit"}}
diff --git a/app/assets/javascripts/admin/templates/embedding.hbs b/app/assets/javascripts/admin/templates/embedding.hbs
index 196ada30f..5db5cb6bf 100644
--- a/app/assets/javascripts/admin/templates/embedding.hbs
+++ b/app/assets/javascripts/admin/templates/embedding.hbs
@@ -2,9 +2,10 @@
{{#if embedding.embeddable_hosts}}
- {{i18n "admin.embedding.host"}} |
+ {{i18n "admin.embedding.host"}} |
+ {{i18n "admin.embedding.path_whitelist"}} |
{{i18n "admin.embedding.category"}} |
- |
+ |
{{#each embedding.embeddable_hosts as |host|}}
{{embeddable-host host=host deleteHost="deleteHost"}}
diff --git a/app/controllers/admin/embeddable_hosts_controller.rb b/app/controllers/admin/embeddable_hosts_controller.rb
index 2d90d46f2..7f15c9fd0 100644
--- a/app/controllers/admin/embeddable_hosts_controller.rb
+++ b/app/controllers/admin/embeddable_hosts_controller.rb
@@ -21,6 +21,7 @@ class Admin::EmbeddableHostsController < Admin::AdminController
def save_host(host)
host.host = params[:embeddable_host][:host]
+ host.path_whitelist = params[:embeddable_host][:path_whitelist]
host.category_id = params[:embeddable_host][:category_id]
host.category_id = SiteSetting.uncategorized_category_id if host.category_id.blank?
diff --git a/app/controllers/embed_controller.rb b/app/controllers/embed_controller.rb
index dd66c7e7e..f9daccb48 100644
--- a/app/controllers/embed_controller.rb
+++ b/app/controllers/embed_controller.rb
@@ -85,7 +85,7 @@ class EmbedController < ApplicationController
def ensure_embeddable
if !(Rails.env.development? && current_user.try(:admin?))
- raise Discourse::InvalidAccess.new('invalid referer host') unless EmbeddableHost.host_allowed?(request.referer)
+ raise Discourse::InvalidAccess.new('invalid referer host') unless EmbeddableHost.url_allowed?(request.referer)
end
response.headers['X-Frame-Options'] = "ALLOWALL"
diff --git a/app/models/embeddable_host.rb b/app/models/embeddable_host.rb
index d42879ad9..b70bf3220 100644
--- a/app/models/embeddable_host.rb
+++ b/app/models/embeddable_host.rb
@@ -7,8 +7,11 @@ class EmbeddableHost < ActiveRecord::Base
self.host.sub!(/\/.*$/, '')
end
- def self.record_for_host(host)
- uri = URI(host) rescue nil
+ def self.record_for_url(uri)
+
+ if uri.is_a?(String)
+ uri = URI(uri) rescue nil
+ end
return false unless uri.present?
host = uri.host
@@ -17,8 +20,13 @@ class EmbeddableHost < ActiveRecord::Base
where("lower(host) = ?", host).first
end
- def self.host_allowed?(host)
- record_for_host(host).present?
+ def self.url_allowed?(url)
+ uri = URI(url) rescue nil
+ return false unless uri.present?
+
+ host = record_for_url(uri)
+ return host.present? &&
+ (host.path_whitelist.blank? || !Regexp.new(host.path_whitelist).match(uri.path).nil?)
end
private
diff --git a/app/models/topic_embed.rb b/app/models/topic_embed.rb
index f98bd984c..4d2e4a956 100644
--- a/app/models/topic_embed.rb
+++ b/app/models/topic_embed.rb
@@ -33,7 +33,7 @@ class TopicEmbed < ActiveRecord::Base
# If there is no embed, create a topic, post and the embed.
if embed.blank?
Topic.transaction do
- eh = EmbeddableHost.record_for_host(url)
+ eh = EmbeddableHost.record_for_url(url)
creator = PostCreator.new(user,
title: title,
diff --git a/app/serializers/embeddable_host_serializer.rb b/app/serializers/embeddable_host_serializer.rb
index f5de82a0c..61cf16e69 100644
--- a/app/serializers/embeddable_host_serializer.rb
+++ b/app/serializers/embeddable_host_serializer.rb
@@ -1,16 +1,11 @@
class EmbeddableHostSerializer < ApplicationSerializer
- attributes :id, :host, :category_id
- def id
- object.id
+ TO_SERIALIZE = [:id, :host, :path_whitelist, :category_id]
+
+ attributes *TO_SERIALIZE
+
+ TO_SERIALIZE.each do |attr|
+ define_method(attr) { object.send(attr) }
end
- def host
- object.host
- end
-
- def category_id
- object.category_id
- end
end
-
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 1613319ba..f5b107a34 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -3113,6 +3113,7 @@ en:
sample: "Use the following HTML code into your site to create and embed discourse topics. Replace REPLACE_ME with the canonical URL of the page you are embedding it on."
title: "Embedding"
host: "Allowed Hosts"
+ path_whitelist: "Path Whitelist"
edit: "edit"
category: "Post to Category"
add_host: "Add Host"
diff --git a/lib/topic_retriever.rb b/lib/topic_retriever.rb
index 2af8401af..fecccb657 100644
--- a/lib/topic_retriever.rb
+++ b/lib/topic_retriever.rb
@@ -7,13 +7,13 @@ class TopicRetriever
end
def retrieve
- perform_retrieve unless (invalid_host? || retrieved_recently?)
+ perform_retrieve unless (invalid_url? || retrieved_recently?)
end
private
- def invalid_host?
- !EmbeddableHost.host_allowed?(@embed_url)
+ def invalid_url?
+ !EmbeddableHost.url_allowed?(@embed_url)
end
def retrieved_recently?
diff --git a/spec/components/topic_retriever_spec.rb b/spec/components/topic_retriever_spec.rb
index 89db716b2..a5180b8c3 100644
--- a/spec/components/topic_retriever_spec.rb
+++ b/spec/components/topic_retriever_spec.rb
@@ -10,7 +10,7 @@ describe TopicRetriever do
describe "#retrieve" do
context "when host is invalid" do
before do
- topic_retriever.stubs(:invalid_host?).returns(true)
+ topic_retriever.stubs(:invalid_url?).returns(true)
end
it "does not perform_retrieve" do
@@ -32,7 +32,7 @@ describe TopicRetriever do
context "when host is not invalid" do
before do
- topic_retriever.stubs(:invalid_host?).returns(false)
+ topic_retriever.stubs(:invalid_url?).returns(false)
end
context "when topics have been retrieived recently" do
diff --git a/spec/models/embeddable_host_spec.rb b/spec/models/embeddable_host_spec.rb
index c6596370a..72d413919 100644
--- a/spec/models/embeddable_host_spec.rb
+++ b/spec/models/embeddable_host_spec.rb
@@ -49,19 +49,28 @@ describe EmbeddableHost do
expect(eh).not_to be_valid
end
- describe "allows_embeddable_host" do
+ describe "url_allowed?" do
let!(:host) { Fabricate(:embeddable_host) }
it 'works as expected' do
- expect(EmbeddableHost.host_allowed?('http://eviltrout.com')).to eq(true)
- expect(EmbeddableHost.host_allowed?('https://eviltrout.com')).to eq(true)
- expect(EmbeddableHost.host_allowed?('https://not-eviltrout.com')).to eq(false)
+ expect(EmbeddableHost.url_allowed?('http://eviltrout.com')).to eq(true)
+ expect(EmbeddableHost.url_allowed?('https://eviltrout.com')).to eq(true)
+ expect(EmbeddableHost.url_allowed?('https://not-eviltrout.com')).to eq(false)
end
it 'works with multiple hosts' do
Fabricate(:embeddable_host, host: 'discourse.org')
- expect(EmbeddableHost.host_allowed?('http://eviltrout.com')).to eq(true)
- expect(EmbeddableHost.host_allowed?('http://discourse.org')).to eq(true)
+ expect(EmbeddableHost.url_allowed?('http://eviltrout.com')).to eq(true)
+ expect(EmbeddableHost.url_allowed?('http://discourse.org')).to eq(true)
+ end
+ end
+
+ describe "path_whitelist" do
+ let!(:host) { Fabricate(:embeddable_host, path_whitelist: '^/fp/\d{4}/\d{2}/\d{2}/.*$') }
+
+ it "matches the path" do
+ expect(EmbeddableHost.url_allowed?('http://eviltrout.com')).to eq(false)
+ expect(EmbeddableHost.url_allowed?('http://eviltrout.com/fp/2016/08/25/test-page')).to eq(true)
end
end
|