Add status destroy authorization to policy (#3453)

* Add status destroy authorization to policy

* Create explicit unreblog status authorization
This commit is contained in:
Jack Jennings 2017-05-30 13:56:31 -07:00 committed by Eugen Rochko
parent 3576fa0d59
commit 33f669a5f8
6 changed files with 78 additions and 5 deletions

View file

@ -2,6 +2,8 @@
module Admin module Admin
class ReportedStatusesController < BaseController class ReportedStatusesController < BaseController
include Authorization
before_action :set_report before_action :set_report
before_action :set_status before_action :set_status
@ -11,6 +13,7 @@ module Admin
end end
def destroy def destroy
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id) RemovalWorker.perform_async(@status.id)
redirect_to admin_report_path(@report) redirect_to admin_report_path(@report)
end end

View file

@ -79,7 +79,10 @@ class Api::V1::StatusesController < ApiController
def destroy def destroy
@status = Status.where(account_id: current_user.account).find(params[:id]) @status = Status.where(account_id: current_user.account).find(params[:id])
authorize @status, :destroy?
RemovalWorker.perform_async(@status.id) RemovalWorker.perform_async(@status.id)
render_empty render_empty
end end
@ -93,6 +96,8 @@ class Api::V1::StatusesController < ApiController
@status = reblog.reblog @status = reblog.reblog
@reblogs_map = { @status.id => false } @reblogs_map = { @status.id => false }
authorize reblog, :unreblog?
RemovalWorker.perform_async(reblog.id) RemovalWorker.perform_async(reblog.id)
render :show render :show

View file

@ -10,9 +10,9 @@ class StatusPolicy
def show? def show?
if direct? if direct?
status.account.id == account&.id || status.mentions.where(account: account).exists? owned? || status.mentions.where(account: account).exists?
elsif private? elsif private?
status.account.id == account&.id || account&.following?(status.account) || status.mentions.where(account: account).exists? owned? || account&.following?(status.account) || status.mentions.where(account: account).exists?
else else
account.nil? || !status.account.blocking?(account) account.nil? || !status.account.blocking?(account)
end end
@ -22,12 +22,26 @@ class StatusPolicy
!direct? && !private? && show? !direct? && !private? && show?
end end
def destroy?
admin? || owned?
end
alias unreblog? destroy?
private private
def admin?
account&.user&.admin?
end
def direct? def direct?
status.direct_visibility? status.direct_visibility?
end end
def owned?
status.account.id == account&.id
end
def private? def private?
status.private_visibility? status.private_visibility?
end end

View file

@ -2,6 +2,7 @@
class ProcessInteractionService < BaseService class ProcessInteractionService < BaseService
include AuthorExtractor include AuthorExtractor
include Authorization
# Record locally the remote interaction with our user # Record locally the remote interaction with our user
# @param [String] envelope Salmon envelope # @param [String] envelope Salmon envelope
@ -46,7 +47,7 @@ class ProcessInteractionService < BaseService
reflect_unblock!(account, target_account) reflect_unblock!(account, target_account)
end end
end end
rescue Goldfinger::Error, HTTP::Error, OStatus2::BadSalmonError rescue Goldfinger::Error, HTTP::Error, OStatus2::BadSalmonError, Mastodon::NotPermittedError
nil nil
end end
@ -103,7 +104,9 @@ class ProcessInteractionService < BaseService
return if status.nil? return if status.nil?
RemovalWorker.perform_async(status.id) if account.id == status.account_id authorize_with account, status, :destroy?
RemovalWorker.perform_async(status.id)
end end
def favourite!(xml, from_account) def favourite!(xml, from_account)

View file

@ -4,7 +4,9 @@ require 'pundit/rspec'
RSpec.describe StatusPolicy, type: :model do RSpec.describe StatusPolicy, type: :model do
subject { described_class } subject { described_class }
let(:admin) { Fabricate(:user, admin: true) }
let(:alice) { Fabricate(:account, username: 'alice') } let(:alice) { Fabricate(:account, username: 'alice') }
let(:bob) { Fabricate(:account, username: 'bob') }
let(:status) { Fabricate(:status, account: alice) } let(:status) { Fabricate(:status, account: alice) }
permissions :show?, :reblog? do permissions :show?, :reblog? do
@ -86,4 +88,22 @@ RSpec.describe StatusPolicy, type: :model do
expect(subject).to_not permit(viewer, status) expect(subject).to_not permit(viewer, status)
end end
end end
permissions :destroy?, :unreblog? do
it 'grants access when account is deleter' do
expect(subject).to permit(status.account, status)
end
it 'grants access when account is admin' do
expect(subject).to permit(admin.account, status)
end
it 'denies access when account is not deleter' do
expect(subject).to_not permit(bob, status)
end
it 'denies access when no deleter' do
expect(subject).to_not permit(nil, status)
end
end
end end

View file

@ -7,6 +7,35 @@ RSpec.describe ProcessInteractionService do
subject { ProcessInteractionService.new } subject { ProcessInteractionService.new }
describe 'status delete slap' do
let(:remote_status) { Fabricate(:status, account: remote_sender) }
let(:envelope) { OStatus2::Salmon.new.pack(payload, sender.keypair) }
let(:payload) {
<<~XML
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
<author>
<email>carol@localdomain.com</email>
<name>carol</name>
<uri>https://webdomain.com/users/carol</uri>
</author>
<id>#{remote_status.id}</id>
<activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
</entry>
XML
}
before do
receiver.update(locked: true)
remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key)
end
it 'deletes a record' do
expect(RemovalWorker).to receive(:perform_async).with(remote_status.id)
subject.call(envelope, receiver)
end
end
describe 'follow request slap' do describe 'follow request slap' do
before do before do
receiver.update(locked: true) receiver.update(locked: true)
@ -60,7 +89,6 @@ XML
end end
end end
describe 'follow request authorization slap' do describe 'follow request authorization slap' do
before do before do
receiver.update(locked: true) receiver.update(locked: true)