about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorFire Demon <firedemon@creature.cafe>2020-07-21 14:53:41 -0500
committerFire Demon <firedemon@creature.cafe>2020-08-30 05:44:01 -0500
commit3f79c75942de0098d582916af3d12f506394d97d (patch)
tree2c2ae771b61a02dbf5ac72b4dd2b91f62c4f4e36 /app
parentbbe174b422b3c72eda966fd6c31a6484fffdf753 (diff)
[Privacy] Limit visibility of replies to private threads and branches
Diffstat (limited to 'app')
-rw-r--r--app/models/status.rb9
-rw-r--r--app/policies/status_policy.rb27
2 files changed, 31 insertions, 5 deletions
diff --git a/app/models/status.rb b/app/models/status.rb
index 74012c22e..120a69715 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -30,6 +30,7 @@
 #  published              :boolean          default(TRUE), not null
 #
 
+# rubocop:disable Metrics/ClassLength
 class Status < ApplicationRecord
   before_destroy :unlink_from_conversations
 
@@ -289,8 +290,8 @@ class Status < ApplicationRecord
 
   before_validation :prepare_contents, if: :local?
   before_validation :set_reblog
-  before_validation :set_visibility
   before_validation :set_conversation
+  before_validation :set_visibility
   before_validation :set_local
 
   after_create :set_poll_id
@@ -422,14 +423,14 @@ class Status < ApplicationRecord
       else
         # followers can see followers-only stuff, but also things they are mentioned in.
         # non-followers can see everything that isn't private/direct, but can see stuff they are mentioned in.
-        visibility.push(:private) if account.following?(target_account) && (user_signed_in || target_account.show_unlisted?)
-
         scope = left_outer_joins(:reblog).published
 
         scope = scope.where(visibility: visibility)
                      .or(scope.where(id: account.mentions.select(:status_id)))
                      .merge(scope.where(reblog_of_id: nil).or(scope.where.not(reblogs_statuses: { account_id: account.excluded_from_timeline_account_ids })))
 
+        scope = scope.or(scope.where(visibility: :private).without_replies) if account.following?(target_account)
+
         apply_timeline_filters(scope, account, false)
       end
     end
@@ -539,6 +540,7 @@ class Status < ApplicationRecord
   def set_visibility
     self.visibility = reblog.visibility if reblog? && visibility.nil?
     self.visibility = (account.locked? ? :private : :public) if visibility.nil?
+    self.visibility = thread.visibility unless thread.nil? || %w(public unlisted).include?(thread.visibility) || ['direct', 'limited', thread.visibility].include?(visibility.to_s)
     self.sensitive  = false if sensitive.nil?
   end
 
@@ -614,3 +616,4 @@ class Status < ApplicationRecord
     end
   end
 end
+# rubocop:enable Metrics/ClassLength
\ No newline at end of file
diff --git a/app/policies/status_policy.rb b/app/policies/status_policy.rb
index 9c98b0688..22e985b03 100644
--- a/app/policies/status_policy.rb
+++ b/app/policies/status_policy.rb
@@ -18,9 +18,9 @@ class StatusPolicy < ApplicationPolicy
     if requires_mention?
       owned? || mention_exists?
     elsif private?
-      owned? || following_author? || mention_exists?
+      owned? || (following_author? && following_parent_author?) || mention_exists?
     else
-      current_account.nil? || (!author_blocking? && !author_blocking_domain?)
+      current_account.nil? || !(author_blocking? || parent_author_blocking? || author_blocking_domain? || parent_author_blocking_domain?)
     end
   end
 
@@ -72,6 +72,12 @@ class StatusPolicy < ApplicationPolicy
     author.domain_blocking?(current_account.domain)
   end
 
+  def parent_author_blocking_domain?
+    return false if current_account.nil? || current_account.domain.nil? || parent_author.nil?
+
+    parent_author.domain_blocking?(current_account.domain)
+  end
+
   def blocking_author?
     return false if current_account.nil?
 
@@ -84,15 +90,32 @@ class StatusPolicy < ApplicationPolicy
     @preloaded_relations[:blocked_by] ? @preloaded_relations[:blocked_by][author.id] : author.blocking?(current_account)
   end
 
+  def parent_author_blocking?
+    return false if current_account.nil? || parent_author.nil?
+
+    @preloaded_relations[:blocked_by] ? @preloaded_relations[:blocked_by][parent_author.id] : parent_author.blocking?(current_account)
+  end
+
   def following_author?
     return false if current_account.nil?
 
     @preloaded_relations[:following] ? @preloaded_relations[:following][author.id] : current_account.following?(author)
   end
 
+  def following_parent_author?
+    return false if current_account.nil?
+    return true if parent_author.nil?
+
+    @preloaded_relations[:following] ? @preloaded_relations[:following][parent_author.id] : current_account.following?(parent_author)
+  end
+
   def author
     record.account
   end
+
+  def parent_author
+    record.in_reply_to_account
+  end
   
   def local_only?
     record.local_only?