Extract authorization policy for viewing statuses (#3150)
parent
9a81be0d37
commit
3a2003ba86
@ -0,0 +1,22 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
module Authorization |
||||
extend ActiveSupport::Concern |
||||
include Pundit |
||||
|
||||
def pundit_user |
||||
current_account |
||||
end |
||||
|
||||
def authorize(*) |
||||
super |
||||
rescue Pundit::NotAuthorizedError |
||||
raise Mastodon::NotPermittedError |
||||
end |
||||
|
||||
def authorize_with(user, record, query) |
||||
Pundit.authorize(user, record, query) |
||||
rescue Pundit::NotAuthorizedError |
||||
raise Mastodon::NotPermittedError |
||||
end |
||||
end |
@ -0,0 +1,20 @@ |
||||
# frozen_string_literal: true |
||||
|
||||
class StatusPolicy |
||||
attr_reader :account, :status |
||||
|
||||
def initialize(account, status) |
||||
@account = account |
||||
@status = status |
||||
end |
||||
|
||||
def show? |
||||
if status.direct_visibility? |
||||
status.account.id == account&.id || status.mentions.where(account: account).exists? |
||||
elsif status.private_visibility? |
||||
status.account.id == account&.id || account&.following?(status.account) || status.mentions.where(account: account).exists? |
||||
else |
||||
account.nil? || !status.account.blocking?(account) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,70 @@ |
||||
require 'rails_helper' |
||||
require 'pundit/rspec' |
||||
|
||||
RSpec.describe StatusPolicy, type: :model do |
||||
subject { described_class } |
||||
|
||||
let(:alice) { Fabricate(:account, username: 'alice') } |
||||
let(:status) { Fabricate(:status, account: alice) } |
||||
|
||||
permissions :show? do |
||||
it 'grants access when direct and account is viewer' do |
||||
status.visibility = :direct |
||||
expect(subject).to permit(status.account, status) |
||||
end |
||||
|
||||
it 'grants access when direct and viewer is mentioned' do |
||||
status.visibility = :direct |
||||
status.mentions = [Fabricate(:mention, account: alice)] |
||||
|
||||
expect(subject).to permit(alice, status) |
||||
end |
||||
|
||||
it 'denies access when direct and viewer is not mentioned' do |
||||
viewer = Fabricate(:account) |
||||
status.visibility = :direct |
||||
|
||||
expect(subject).to_not permit(viewer, status) |
||||
end |
||||
|
||||
it 'grants access when private and account is viewer' do |
||||
status.visibility = :direct |
||||
|
||||
expect(subject).to permit(status.account, status) |
||||
end |
||||
|
||||
it 'grants access when private and account is following viewer' do |
||||
follow = Fabricate(:follow) |
||||
status.visibility = :private |
||||
status.account = follow.target_account |
||||
|
||||
expect(subject).to permit(follow.account, status) |
||||
end |
||||
|
||||
it 'grants access when private and viewer is mentioned' do |
||||
status.visibility = :private |
||||
status.mentions = [Fabricate(:mention, account: alice)] |
||||
|
||||
expect(subject).to permit(alice, status) |
||||
end |
||||
|
||||
it 'denies access when private and viewer is not mentioned or followed' do |
||||
viewer = Fabricate(:account) |
||||
status.visibility = :private |
||||
|
||||
expect(subject).to_not permit(viewer, status) |
||||
end |
||||
|
||||
it 'grants access when no viewer' do |
||||
expect(subject).to permit(nil, status) |
||||
end |
||||
|
||||
it 'denies access when viewer is blocked' do |
||||
block = Fabricate(:block) |
||||
status.visibility = :private |
||||
status.account = block.target_account |
||||
|
||||
expect(subject).to_not permit(block.account, status) |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue