From 707ddf7808f90e3ab042d7642d368c2ce8e95e6f Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sat, 22 Jun 2019 00:13:10 +0200 Subject: Change domain blocks to automatically support subdomains (#11138) * Change domain blocks to automatically support subdomains If a more authoritative domain is blocked (example.com), then the same block will be applied to a subdomain (foo.example.com) * Match subdomains of existing accounts when blocking/unblocking domains * Improve code style --- app/models/account.rb | 1 + app/models/custom_emoji.rb | 1 + app/models/domain_block.rb | 33 ++++++++++++++++++++++++++++++--- app/models/instance.rb | 2 +- 4 files changed, 33 insertions(+), 4 deletions(-) (limited to 'app/models') diff --git a/app/models/account.rb b/app/models/account.rb index 9276aa927..c588451fc 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -98,6 +98,7 @@ class Account < ApplicationRecord scope :tagged_with, ->(tag) { joins(:accounts_tags).where(accounts_tags: { tag_id: tag }) } scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc')) } scope :popular, -> { order('account_stats.followers_count desc') } + scope :by_domain_and_subdomains, ->(domain) { where(domain: domain).or(where(arel_table[:domain].matches('%.' + domain))) } delegate :email, :unconfirmed_email, diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index d3cc70504..e73cd9bd2 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -39,6 +39,7 @@ class CustomEmoji < ApplicationRecord scope :local, -> { where(domain: nil) } scope :remote, -> { where.not(domain: nil) } scope :alphabetic, -> { order(domain: :asc, shortcode: :asc) } + scope :by_domain_and_subdomains, ->(domain) { where(domain: domain).or(where(arel_table[:domain].matches('%.' + domain))) } remotable_attachment :image, LIMIT diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb index 84c08c158..25d3b87ef 100644 --- a/app/models/domain_block.rb +++ b/app/models/domain_block.rb @@ -24,14 +24,41 @@ class DomainBlock < ApplicationRecord scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) } - def self.blocked?(domain) - where(domain: domain, severity: :suspend).exists? + class << self + def suspend?(domain) + !!rule_for(domain)&.suspend? + end + + def silence?(domain) + !!rule_for(domain)&.silence? + end + + def reject_media?(domain) + !!rule_for(domain)&.reject_media? + end + + def reject_reports?(domain) + !!rule_for(domain)&.reject_reports? + end + + alias blocked? suspend? + + def rule_for(domain) + return if domain.blank? + + uri = Addressable::URI.new.tap { |u| u.host = domain.gsub(/[\/]/, '') } + segments = uri.normalized_host.split('.') + variants = segments.map.with_index { |_, i| segments[i..-1].join('.') } + + where(domain: variants[0..-2]).order(Arel.sql('char_length(domain) desc')).first + end end def stricter_than?(other_block) - return true if suspend? + return true if suspend? return false if other_block.suspend? && (silence? || noop?) return false if other_block.silence? && noop? + (reject_media || !other_block.reject_media) && (reject_reports || !other_block.reject_reports) end diff --git a/app/models/instance.rb b/app/models/instance.rb index 7bf000d40..a01db1212 100644 --- a/app/models/instance.rb +++ b/app/models/instance.rb @@ -8,7 +8,7 @@ class Instance def initialize(resource) @domain = resource.domain @accounts_count = resource.is_a?(DomainBlock) ? nil : resource.accounts_count - @domain_block = resource.is_a?(DomainBlock) ? resource : DomainBlock.find_by(domain: domain) + @domain_block = resource.is_a?(DomainBlock) ? resource : DomainBlock.rule_for(domain) end def cached_sample_accounts -- cgit