FEATURE: New site setting, whitelisted_link_domains

If provided, users who normally couldn't post links (say, due to a
low trust level), can post links to those specific hosts.
This commit is contained in:
Robin Ward 2018-06-13 14:57:32 -04:00
parent debbb5be16
commit fd54c92a52
10 changed files with 96 additions and 21 deletions

View File

@ -47,6 +47,11 @@ export default Ember.Component.extend({
} }
}, },
@computed
showLink() {
return this.currentUser && this.currentUser.get('link_posting_access') !== 'none';
},
@computed('composer.requiredCategoryMissing', 'composer.replyLength') @computed('composer.requiredCategoryMissing', 'composer.replyLength')
disableTextarea(requiredCategoryMissing, replyLength) { disableTextarea(requiredCategoryMissing, replyLength) {
return requiredCategoryMissing && replyLength === 0; return requiredCategoryMissing && replyLength === 0;

View File

@ -11,7 +11,7 @@
validation=validation validation=validation
loading=composer.loading loading=composer.loading
forcePreview=forcePreview forcePreview=forcePreview
showLink=currentUser.can_post_link showLink=showLink
composerEvents=true composerEvents=true
onExpandPopupMenuOptions="onExpandPopupMenuOptions" onExpandPopupMenuOptions="onExpandPopupMenuOptions"
onPopupMenuAction=onPopupMenuAction onPopupMenuAction=onPopupMenuAction

View File

@ -6,11 +6,11 @@ class PostAnalyzer
def initialize(raw, topic_id) def initialize(raw, topic_id)
@raw = raw @raw = raw
@topic_id = topic_id @topic_id = topic_id
@found_oneboxes = false @onebox_urls = []
end end
def found_oneboxes? def found_oneboxes?
@found_oneboxes @onebox_urls.present?
end end
def has_oneboxes? def has_oneboxes?
@ -32,7 +32,7 @@ class PostAnalyzer
end end
result = Oneboxer.apply(cooked) do |url| result = Oneboxer.apply(cooked) do |url|
@found_oneboxes = true @onebox_urls << url
Oneboxer.invalidate(url) if opts[:invalidate_oneboxes] Oneboxer.invalidate(url) if opts[:invalidate_oneboxes]
Oneboxer.cached_onebox(url) Oneboxer.cached_onebox(url)
end end
@ -86,18 +86,20 @@ class PostAnalyzer
# Count how many hosts are linked in the post # Count how many hosts are linked in the post
def linked_hosts def linked_hosts
return {} if raw_links.blank? all_links = raw_links + @onebox_urls
return {} if all_links.blank?
return @linked_hosts if @linked_hosts.present? return @linked_hosts if @linked_hosts.present?
@linked_hosts = {} @linked_hosts = {}
raw_links.each do |u| all_links.each do |u|
begin begin
uri = self.class.parse_uri_rfc2396(u) uri = self.class.parse_uri_rfc2396(u)
host = uri.host host = uri.host
@linked_hosts[host] ||= 1 unless host.nil? @linked_hosts[host] ||= 1 unless host.nil?
rescue URI::InvalidURIError rescue URI::InvalidURIError, URI::InvalidComponentError
# An invalid URI does not count as a raw link. # An invalid URI does not count as a host
next next
end end
end end

View File

@ -40,11 +40,11 @@ class CurrentUserSerializer < BasicUserSerializer
:primary_group_id, :primary_group_id,
:primary_group_name, :primary_group_name,
:can_create_topic, :can_create_topic,
:can_post_link, :link_posting_access,
:external_id :external_id
def can_post_link def link_posting_access
scope.can_post_link? scope.link_posting_access
end end
def can_create_topic def can_create_topic

View File

@ -1394,6 +1394,8 @@ en:
min_trust_to_post_links: "The minimum trust level required to include links in posts" min_trust_to_post_links: "The minimum trust level required to include links in posts"
min_trust_to_post_images: "The minimum trust level required to include images in a post" min_trust_to_post_images: "The minimum trust level required to include images in a post"
whitelisted_link_domains: "Domains that users may link to even if they don't have the appropriate trust level to post links"
newuser_max_links: "How many links a new user can add to a post." newuser_max_links: "How many links a new user can add to a post."
newuser_max_images: "How many images a new user can add to a post." newuser_max_images: "How many images a new user can add to a post."
newuser_max_attachments: "How many attachments a new user can add to a post." newuser_max_attachments: "How many attachments a new user can add to a post."

View File

@ -614,6 +614,9 @@ posting:
newuser_max_replies_per_topic: 3 newuser_max_replies_per_topic: 3
newuser_max_mentions_per_post: 2 newuser_max_mentions_per_post: 2
title_max_word_length: 30 title_max_word_length: 30
whitelisted_link_domains:
default: ''
type: list
newuser_max_links: 2 newuser_max_links: 2
newuser_max_images: newuser_max_images:
client: true client: true

View File

@ -1,9 +1,25 @@
#mixin for all guardian methods dealing with post permissions #mixin for all guardian methods dealing with post permissions
module PostGuardian module PostGuardian
def can_post_link? def unrestricted_link_posting?
authenticated? && authenticated? && @user.has_trust_level?(TrustLevel[SiteSetting.min_trust_to_post_links])
@user.has_trust_level?(TrustLevel[SiteSetting.min_trust_to_post_links]) end
def link_posting_access
if unrestricted_link_posting?
'full'
elsif SiteSetting.whitelisted_link_domains.present?
'limited'
else
'none'
end
end
def can_post_link?(host: nil)
return false if host.blank?
unrestricted_link_posting? ||
SiteSetting.whitelisted_link_domains.split('|').include?(host)
end end
# Can the user act on the post in a particular way. # Can the user act on the post in a particular way.

View File

@ -109,10 +109,12 @@ class Validators::PostValidator < ActiveModel::Validator
end end
def can_post_links_validator(post) def can_post_links_validator(post)
if (post.link_count == 0 && !post.has_oneboxes?) || if (post.link_count == 0 && !post.has_oneboxes?) || private_message?(post)
Guardian.new(post.acting_user).can_post_link? || return newuser_links_validator(post)
private_message?(post) end
guardian = Guardian.new(post.acting_user)
if post.linked_hosts.keys.all? { |h| guardian.can_post_link?(host: h) }
return newuser_links_validator(post) return newuser_links_validator(post)
end end

View File

@ -26,21 +26,59 @@ describe Guardian do
expect { Guardian.new(user) }.not_to raise_error expect { Guardian.new(user) }.not_to raise_error
end end
describe "link_posting_access" do
it "is none for anonymous users" do
expect(Guardian.new.link_posting_access).to eq('none')
end
it "is full for regular users" do
expect(Guardian.new(user).link_posting_access).to eq('full')
end
it "is none for a user of a low trust level" do
user.trust_level = 0
SiteSetting.min_trust_to_post_links = 1
expect(Guardian.new(user).link_posting_access).to eq('none')
end
it "is limited for a user of a low trust level with a whitelist" do
SiteSetting.whitelisted_link_domains = 'example.com'
user.trust_level = 0
SiteSetting.min_trust_to_post_links = 1
expect(Guardian.new(user).link_posting_access).to eq('limited')
end
end
describe "can_post_link?" do describe "can_post_link?" do
let(:host) { "discourse.org" }
it "returns false for anonymous users" do it "returns false for anonymous users" do
expect(Guardian.new.can_post_link?).to eq(false) expect(Guardian.new.can_post_link?(host: host)).to eq(false)
end end
it "returns true for a regular user" do it "returns true for a regular user" do
expect(Guardian.new(user).can_post_link?).to eq(true) expect(Guardian.new(user).can_post_link?(host: host)).to eq(true)
end end
it "supports customization by site setting" do it "supports customization by site setting" do
user.trust_level = 0 user.trust_level = 0
SiteSetting.min_trust_to_post_links = 0 SiteSetting.min_trust_to_post_links = 0
expect(Guardian.new(user).can_post_link?).to eq(true) expect(Guardian.new(user).can_post_link?(host: host)).to eq(true)
SiteSetting.min_trust_to_post_links = 1 SiteSetting.min_trust_to_post_links = 1
expect(Guardian.new(user).can_post_link?).to eq(false) expect(Guardian.new(user).can_post_link?(host: host)).to eq(false)
end
describe "whitelisted host" do
before do
SiteSetting.whitelisted_link_domains = host
end
it "allows a new user to post the link to the host" do
user.trust_level = 0
SiteSetting.min_trust_to_post_links = 1
expect(Guardian.new(user).can_post_link?(host: host)).to eq(true)
expect(Guardian.new(user).can_post_link?(host: 'another-host.com')).to eq(false)
end
end end
end end

View File

@ -452,6 +452,13 @@ describe Post do
post_two_links.user.trust_level = TrustLevel[1] post_two_links.user.trust_level = TrustLevel[1]
expect(post_one_link).not_to be_valid expect(post_one_link).not_to be_valid
end end
it "will skip the check for whitelisted domains" do
SiteSetting.whitelisted_link_domains = 'www.bbc.co.uk'
SiteSetting.min_trust_to_post_links = 2
post_two_links.user.trust_level = TrustLevel[1]
expect(post_one_link).to be_valid
end
end end
end end