Merge branch 'master' into feature-limited-visibility-bearcaps

This commit is contained in:
Takeshi Umeda 2021-01-10 11:17:55 +09:00 committed by GitHub
commit 98a2603dc1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
855 changed files with 32564 additions and 10102 deletions

View file

@ -16,17 +16,49 @@ describe AccountFollowController do
allow(service).to receive(:call)
end
it 'does not create for user who is not signed in' do
subject
expect(FollowService).not_to receive(:new)
context 'when account is permanently suspended' do
before do
alice.suspend!
alice.deletion_request.destroy
subject
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
it 'redirects to account path' do
sign_in(user)
subject
context 'when account is temporarily suspended' do
before do
alice.suspend!
subject
end
expect(service).to have_received(:call).with(user.account, alice, with_rate_limit: true)
expect(response).to redirect_to(account_path(alice))
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
context 'when signed out' do
before do
subject
end
it 'does not follow' do
expect(FollowService).not_to receive(:new)
end
end
context 'when signed in' do
before do
sign_in(user)
subject
end
it 'redirects to account path' do
expect(service).to have_received(:call).with(user.account, alice, with_rate_limit: true)
expect(response).to redirect_to(account_path(alice))
end
end
end
end

View file

@ -16,17 +16,49 @@ describe AccountUnfollowController do
allow(service).to receive(:call)
end
it 'does not create for user who is not signed in' do
subject
expect(UnfollowService).not_to receive(:new)
context 'when account is permanently suspended' do
before do
alice.suspend!
alice.deletion_request.destroy
subject
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
it 'redirects to account path' do
sign_in(user)
subject
context 'when account is temporarily suspended' do
before do
alice.suspend!
subject
end
expect(service).to have_received(:call).with(user.account, alice)
expect(response).to redirect_to(account_path(alice))
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
context 'when signed out' do
before do
subject
end
it 'does not unfollow' do
expect(UnfollowService).not_to receive(:new)
end
end
context 'when signed in' do
before do
sign_in(user)
subject
end
it 'redirects to account path' do
expect(service).to have_received(:call).with(user.account, alice)
expect(response).to redirect_to(account_path(alice))
end
end
end
end

View file

@ -48,10 +48,17 @@ RSpec.describe AccountsController, type: :controller do
expect(response).to have_http_status(404)
end
end
end
context 'when account is suspended' do
context 'as HTML' do
let(:format) { 'html' }
it_behaves_like 'preliminary checks'
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
@ -59,12 +66,17 @@ RSpec.describe AccountsController, type: :controller do
expect(response).to have_http_status(410)
end
end
end
context 'as HTML' do
let(:format) { 'html' }
context 'when account is temporarily suspended' do
before do
account.suspend!
end
it_behaves_like 'preliminary checks'
it 'returns http forbidden' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(403)
end
end
shared_examples 'common response characteristics' do
it 'returns http success' do
@ -325,6 +337,29 @@ RSpec.describe AccountsController, type: :controller do
it_behaves_like 'preliminary checks'
context 'when account is suspended permanently' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(410)
end
end
context 'when account is suspended temporarily' do
before do
account.suspend!
end
it 'returns http success' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(200)
end
end
context do
before do
get :show, params: { username: account.username, format: format }
@ -348,24 +383,8 @@ RSpec.describe AccountsController, type: :controller do
context 'in authorized fetch mode' do
let(:authorized_fetch_mode) { true }
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.content_type).to eq 'application/activity+json'
end
it_behaves_like 'cachable response'
it 'returns Vary header with Signature' do
expect(response.headers['Vary']).to include 'Signature'
end
it 'renders bare minimum account' do
json = body_as_json
expect(json).to include(:id, :type, :preferredUsername, :inbox, :publicKey)
expect(json).to_not include(:name, :summary)
it 'returns http unauthorized' do
expect(response).to have_http_status(401)
end
end
end
@ -451,6 +470,29 @@ RSpec.describe AccountsController, type: :controller do
it_behaves_like 'preliminary checks'
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
end
it 'returns http forbidden' do
get :show, params: { username: account.username, format: format }
expect(response).to have_http_status(403)
end
end
shared_examples 'common response characteristics' do
it 'returns http success' do
expect(response).to have_http_status(200)

View file

@ -13,6 +13,7 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
end
it 'does not set sessions' do
response
expect(session).to be_empty
end
@ -34,9 +35,8 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
context 'without signature' do
let(:remote_account) { nil }
before do
get :show, params: { id: 'featured', account_username: account.username }
end
subject(:response) { get :show, params: { id: 'featured', account_username: account.username } }
subject(:body) { body_as_json }
it 'returns http success' do
expect(response).to have_http_status(200)
@ -49,9 +49,29 @@ RSpec.describe ActivityPub::CollectionsController, type: :controller do
it_behaves_like 'cachable response'
it 'returns orderedItems with pinned statuses' do
json = body_as_json
expect(json[:orderedItems]).to be_an Array
expect(json[:orderedItems].size).to eq 2
expect(body[:orderedItems]).to be_an Array
expect(body[:orderedItems].size).to eq 2
end
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end

View file

@ -0,0 +1,77 @@
require 'rails_helper'
RSpec.describe ActivityPub::FollowersSynchronizationsController, type: :controller do
let!(:account) { Fabricate(:account) }
let!(:follower_1) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/a') }
let!(:follower_2) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/users/b') }
let!(:follower_3) { Fabricate(:account, domain: 'foo.com', uri: 'https://foo.com/users/a') }
before do
follower_1.follow!(account)
follower_2.follow!(account)
follower_3.follow!(account)
end
before do
allow(controller).to receive(:signed_request_account).and_return(remote_account)
end
describe 'GET #show' do
context 'without signature' do
let(:remote_account) { nil }
before do
get :show, params: { account_username: account.username }
end
it 'returns http not authorized' do
expect(response).to have_http_status(401)
end
end
context 'with signature from example.com' do
let(:remote_account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/instance') }
subject(:response) { get :show, params: { account_username: account.username } }
subject(:body) { body_as_json }
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns application/activity+json' do
expect(response.content_type).to eq 'application/activity+json'
end
it 'returns orderedItems with followers from example.com' do
expect(body[:orderedItems]).to be_an Array
expect(body[:orderedItems].sort).to eq [follower_1.uri, follower_2.uri]
end
it 'returns private Cache-Control header' do
expect(response.headers['Cache-Control']).to eq 'max-age=0, private'
end
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end
end
end

View file

@ -20,6 +20,83 @@ RSpec.describe ActivityPub::InboxesController, type: :controller do
it 'returns http accepted' do
expect(response).to have_http_status(202)
end
context 'for a specific account' do
let(:account) { Fabricate(:account) }
subject(:response) { post :create, params: { account_username: account.username }, body: '{}' }
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
end
it 'returns http accepted' do
expect(response).to have_http_status(202)
end
end
end
end
context 'with Collection-Synchronization header' do
let(:remote_account) { Fabricate(:account, followers_url: 'https://example.com/followers', domain: 'example.com', uri: 'https://example.com/actor', protocol: :activitypub) }
let(:synchronization_collection) { remote_account.followers_url }
let(:synchronization_url) { 'https://example.com/followers-for-domain' }
let(:synchronization_hash) { 'somehash' }
let(:synchronization_header) { "collectionId=\"#{synchronization_collection}\", digest=\"#{synchronization_hash}\", url=\"#{synchronization_url}\"" }
before do
allow(ActivityPub::FollowersSynchronizationWorker).to receive(:perform_async).and_return(nil)
allow_any_instance_of(Account).to receive(:local_followers_hash).and_return('somehash')
request.headers['Collection-Synchronization'] = synchronization_header
post :create, body: '{}'
end
context 'with mismatching target collection' do
let(:synchronization_collection) { 'https://example.com/followers2' }
it 'does not start a synchronization job' do
expect(ActivityPub::FollowersSynchronizationWorker).not_to have_received(:perform_async)
end
end
context 'with mismatching domain in partial collection attribute' do
let(:synchronization_url) { 'https://example.org/followers' }
it 'does not start a synchronization job' do
expect(ActivityPub::FollowersSynchronizationWorker).not_to have_received(:perform_async)
end
end
context 'with matching digest' do
it 'does not start a synchronization job' do
expect(ActivityPub::FollowersSynchronizationWorker).not_to have_received(:perform_async)
end
end
context 'with mismatching digest' do
let(:synchronization_hash) { 'wronghash' }
it 'starts a synchronization job' do
expect(ActivityPub::FollowersSynchronizationWorker).to have_received(:perform_async)
end
end
it 'returns http accepted' do
expect(response).to have_http_status(202)
end
end
context 'without signature' do

View file

@ -10,6 +10,7 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
end
it 'does not set sessions' do
response
expect(session).to be_empty
end
@ -34,9 +35,8 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
context 'without signature' do
let(:remote_account) { nil }
before do
get :show, params: { account_username: account.username, page: page }
end
subject(:response) { get :show, params: { account_username: account.username, page: page } }
subject(:body) { body_as_json }
context 'with page not requested' do
let(:page) { nil }
@ -50,11 +50,31 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
end
it 'returns totalItems' do
json = body_as_json
expect(json[:totalItems]).to eq 4
expect(body[:totalItems]).to eq 4
end
it_behaves_like 'cachable response'
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end
context 'with page requested' do
@ -69,13 +89,33 @@ RSpec.describe ActivityPub::OutboxesController, type: :controller do
end
it 'returns orderedItems with public or unlisted statuses' do
json = body_as_json
expect(json[:orderedItems]).to be_an Array
expect(json[:orderedItems].size).to eq 2
expect(json[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
expect(body[:orderedItems]).to be_an Array
expect(body[:orderedItems].size).to eq 2
expect(body[:orderedItems].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
end
it_behaves_like 'cachable response'
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end
end

View file

@ -14,6 +14,7 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
end
it 'does not set sessions' do
response
expect(session).to be_empty
end
@ -36,8 +37,32 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
describe 'GET #index' do
context 'with no signature' do
before do
get :index, params: { account_username: status.account.username, status_id: status.id }
subject(:response) { get :index, params: { account_username: status.account.username, status_id: status.id } }
subject(:body) { body_as_json }
context 'when account is permanently suspended' do
let(:parent_visibility) { :public }
before do
status.account.suspend!
status.account.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
let(:parent_visibility) { :public }
before do
status.account.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
context 'when status is public' do
@ -54,12 +79,10 @@ RSpec.describe ActivityPub::RepliesController, type: :controller do
it_behaves_like 'cachable response'
it 'returns items with account\'s own replies' do
json = body_as_json
expect(json[:first]).to be_a Hash
expect(json[:first][:items]).to be_an Array
expect(json[:first][:items].size).to eq 1
expect(json[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
expect(body[:first]).to be_a Hash
expect(body[:first][:items]).to be_an Array
expect(body[:first][:items].size).to eq 1
expect(body[:first][:items].all? { |item| item[:to].include?(ActivityPub::TagManager::COLLECTIONS[:public]) || item[:cc].include?(ActivityPub::TagManager::COLLECTIONS[:public]) }).to be true
end
end

View file

@ -9,10 +9,10 @@ RSpec.describe Admin::InstancesController, type: :controller do
describe 'GET #index' do
around do |example|
default_per_page = Account.default_per_page
Account.paginates_per 1
default_per_page = Instance.default_per_page
Instance.paginates_per 1
example.run
Account.paginates_per default_per_page
Instance.paginates_per default_per_page
end
it 'renders instances' do

View file

@ -71,50 +71,80 @@ RSpec.describe Api::V1::AccountsController, type: :controller do
let(:scopes) { 'write:follows' }
let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', locked: locked)).account }
before do
post :follow, params: { id: other_account.id }
end
context 'with unlocked account' do
let(:locked) { false }
it 'returns http success' do
expect(response).to have_http_status(200)
context do
before do
post :follow, params: { id: other_account.id }
end
it 'returns JSON with following=true and requested=false' do
context 'with unlocked account' do
let(:locked) { false }
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns JSON with following=true and requested=false' do
json = body_as_json
expect(json[:following]).to be true
expect(json[:requested]).to be false
end
it 'creates a following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
end
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
end
context 'with locked account' do
let(:locked) { true }
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns JSON with following=false and requested=true' do
json = body_as_json
expect(json[:following]).to be false
expect(json[:requested]).to be true
end
it 'creates a follow request relation between user and target user' do
expect(user.account.requested?(other_account)).to be true
end
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
end
end
context 'modifying follow options' do
let(:locked) { false }
before do
user.account.follow!(other_account, reblogs: false, notify: false)
end
it 'changes reblogs option' do
post :follow, params: { id: other_account.id, reblogs: true }
json = body_as_json
expect(json[:following]).to be true
expect(json[:requested]).to be false
expect(json[:showing_reblogs]).to be true
expect(json[:notifying]).to be false
end
it 'creates a following relation between user and target user' do
expect(user.account.following?(other_account)).to be true
end
it 'changes notify option' do
post :follow, params: { id: other_account.id, notify: true }
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
end
context 'with locked account' do
let(:locked) { true }
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'returns JSON with following=false and requested=true' do
json = body_as_json
expect(json[:following]).to be false
expect(json[:requested]).to be true
expect(json[:following]).to be true
expect(json[:showing_reblogs]).to be false
expect(json[:notifying]).to be true
end
it 'creates a follow request relation between user and target user' do
expect(user.account.requested?(other_account)).to be true
end
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
end
end

View file

@ -111,7 +111,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
describe 'POST #unsuspend' do
before do
account.touch(:suspended_at)
account.suspend!
post :unsuspend, params: { id: account.id }
end
@ -127,6 +127,24 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
end
end
describe 'POST #unsensitive' do
before do
account.touch(:sensitized_at)
post :unsensitive, params: { id: account.id }
end
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
it_behaves_like 'forbidden for wrong role', 'user'
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'unsensitives account' do
expect(account.reload.sensitized?).to be false
end
end
describe 'POST #unsilence' do
before do
account.touch(:silenced_at)

View file

@ -82,6 +82,31 @@ describe Api::V1::Statuses::FavouritesController do
end
end
context 'with public status when blocked by its author' do
let(:status) { Fabricate(:status) }
before do
FavouriteService.new.call(user.account, status)
status.account.block!(user.account)
post :destroy, params: { status_id: status.id }
end
it 'returns http success' do
expect(response).to have_http_status(200)
end
it 'updates the favourite attribute' do
expect(user.account.favourited?(status)).to be false
end
it 'returns json with updated attributes' do
hash_body = body_as_json
expect(hash_body[:id]).to eq status.id.to_s
expect(hash_body[:favourited]).to be false
end
end
context 'with private status that was not favourited' do
let(:status) { Fabricate(:status, visibility: :private) }

View file

@ -82,6 +82,10 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
describe 'POST #create' do
let(:accept_language) { Rails.application.config.i18n.available_locales.sample.to_s }
before do
session[:registration_form_time] = 5.seconds.ago
end
around do |example|
current_locale = I18n.locale
example.run
@ -191,17 +195,21 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
end
end
context 'approval-based registrations with valid invite' do
context 'approval-based registrations with valid invite and required invite text' do
around do |example|
registrations_mode = Setting.registrations_mode
require_invite_text = Setting.require_invite_text
example.run
Setting.require_invite_text = require_invite_text
Setting.registrations_mode = registrations_mode
end
subject do
inviter = Fabricate(:user, confirmed_at: 2.days.ago)
Setting.registrations_mode = 'approved'
Setting.require_invite_text = true
request.headers["Accept-Language"] = accept_language
invite = Fabricate(:invite, max_uses: nil, expires_at: 1.hour.from_now)
invite = Fabricate(:invite, user: inviter, max_uses: nil, expires_at: 1.hour.from_now)
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', 'invite_code': invite.code, agreement: 'true' } }
end

View file

@ -219,7 +219,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
context 'using a valid OTP' do
before do
post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id }
post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
end
it 'redirects to home' do
@ -234,7 +234,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
context 'when the server has an decryption error' do
before do
allow_any_instance_of(User).to receive(:validate_and_consume_otp!).and_raise(OpenSSL::Cipher::CipherError)
post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id }
post :create, params: { user: { otp_attempt: user.current_otp } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
end
it 'shows a login error' do
@ -248,7 +248,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
context 'using a valid recovery code' do
before do
post :create, params: { user: { otp_attempt: recovery_codes.first } }, session: { attempt_user_id: user.id }
post :create, params: { user: { otp_attempt: recovery_codes.first } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
end
it 'redirects to home' do
@ -262,7 +262,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
context 'using an invalid OTP' do
before do
post :create, params: { user: { otp_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id }
post :create, params: { user: { otp_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
end
it 'shows a login error' do
@ -334,7 +334,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
before do
@controller.session[:webauthn_challenge] = challenge
post :create, params: { user: { credential: fake_credential } }, session: { attempt_user_id: user.id }
post :create, params: { user: { credential: fake_credential } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
end
it 'instructs the browser to redirect to home' do
@ -383,7 +383,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
context 'using a valid sign in token' do
before do
user.generate_sign_in_token && user.save
post :create, params: { user: { sign_in_token_attempt: user.sign_in_token } }, session: { attempt_user_id: user.id }
post :create, params: { user: { sign_in_token_attempt: user.sign_in_token } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
end
it 'redirects to home' do
@ -397,7 +397,7 @@ RSpec.describe Auth::SessionsController, type: :controller do
context 'using an invalid sign in token' do
before do
post :create, params: { user: { sign_in_token_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id }
post :create, params: { user: { sign_in_token_attempt: 'wrongotp' } }, session: { attempt_user_id: user.id, attempt_user_updated_at: user.updated_at.to_s }
end
it 'shows a login error' do

View file

@ -5,6 +5,7 @@ require 'rails_helper'
describe ApplicationController, type: :controller do
controller do
include ExportControllerConcern
def index
send_export_file
end

View file

@ -14,6 +14,27 @@ describe FollowerAccountsController do
context 'when format is html' do
subject(:response) { get :index, params: { account_username: alice.username, format: :html } }
context 'when account is permanently suspended' do
before do
alice.suspend!
alice.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
alice.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
it 'assigns follows' do
expect(response).to have_http_status(200)
@ -48,6 +69,27 @@ describe FollowerAccountsController do
expect(body['totalItems']).to eq 2
expect(body['partOf']).to be_present
end
context 'when account is permanently suspended' do
before do
alice.suspend!
alice.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
alice.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end
context 'without page' do
@ -58,6 +100,27 @@ describe FollowerAccountsController do
expect(body['totalItems']).to eq 2
expect(body['partOf']).to be_blank
end
context 'when account is permanently suspended' do
before do
alice.suspend!
alice.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
alice.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end
end
end

View file

@ -14,6 +14,27 @@ describe FollowingAccountsController do
context 'when format is html' do
subject(:response) { get :index, params: { account_username: alice.username, format: :html } }
context 'when account is permanently suspended' do
before do
alice.suspend!
alice.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
alice.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
it 'assigns follows' do
expect(response).to have_http_status(200)
@ -48,6 +69,27 @@ describe FollowingAccountsController do
expect(body['totalItems']).to eq 2
expect(body['partOf']).to be_present
end
context 'when account is permanently suspended' do
before do
alice.suspend!
alice.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
alice.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end
context 'without page' do
@ -58,6 +100,27 @@ describe FollowingAccountsController do
expect(body['totalItems']).to eq 2
expect(body['partOf']).to be_blank
end
context 'when account is permanently suspended' do
before do
alice.suspend!
alice.deletion_request.destroy
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
context 'when account is temporarily suspended' do
before do
alice.suspend!
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end
end
end

View file

@ -43,8 +43,7 @@ describe RemoteFollowController do
end
it 'renders new when template is nil' do
link_with_nil_template = double(template: nil)
resource_with_link = double(link: link_with_nil_template)
resource_with_link = double(link: nil)
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_return(resource_with_link)
post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
@ -55,8 +54,7 @@ describe RemoteFollowController do
context 'when webfinger values are good' do
before do
link_with_template = double(template: 'http://example.com/follow_me?acct={uri}')
resource_with_link = double(link: link_with_template)
resource_with_link = double(link: 'http://example.com/follow_me?acct={uri}')
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_return(resource_with_link)
post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
end
@ -78,8 +76,8 @@ describe RemoteFollowController do
expect(response).to render_template(:new)
end
it 'renders new with error when goldfinger fails' do
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_raise(Goldfinger::Error)
it 'renders new with error when webfinger fails' do
allow_any_instance_of(WebfingerHelper).to receive(:webfinger!).with('acct:user@example.com').and_raise(Webfinger::Error)
post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
expect(response).to render_template(:new)
@ -96,21 +94,42 @@ describe RemoteFollowController do
end
end
describe 'with a suspended account' do
context 'with a permanently suspended account' do
before do
@account = Fabricate(:account, suspended: true)
@account = Fabricate(:account)
@account.suspend!
@account.deletion_request.destroy
end
it 'returns 410 gone on GET to #new' do
it 'returns http gone on GET to #new' do
get :new, params: { account_username: @account.to_param }
expect(response).to have_http_status(:gone)
expect(response).to have_http_status(410)
end
it 'returns 410 gone on POST to #create' do
it 'returns http gone on POST to #create' do
post :create, params: { account_username: @account.to_param }
expect(response).to have_http_status(:gone)
expect(response).to have_http_status(410)
end
end
context 'with a temporarily suspended account' do
before do
@account = Fabricate(:account)
@account.suspend!
end
it 'returns http forbidden on GET to #new' do
get :new, params: { account_username: @account.to_param }
expect(response).to have_http_status(403)
end
it 'returns http forbidden on POST to #create' do
post :create, params: { account_username: @account.to_param }
expect(response).to have_http_status(403)
end
end
end

View file

@ -77,6 +77,20 @@ describe Settings::DeletesController do
expect(response).to redirect_to settings_delete_path
end
end
context 'when account deletions are disabled' do
around do |example|
open_deletion = Setting.open_deletion
example.run
Setting.open_deletion = open_deletion
end
it 'redirects' do
Setting.open_deletion = false
delete :destroy
expect(response).to redirect_to root_path
end
end
end
context 'when not signed in' do
@ -85,19 +99,5 @@ describe Settings::DeletesController do
expect(response).to redirect_to '/auth/sign_in'
end
end
context do
around do |example|
open_deletion = Setting.open_deletion
example.run
Setting.open_deletion = open_deletion
end
it 'redirects' do
Setting.open_deletion = false
delete :destroy
expect(response).to redirect_to root_path
end
end
end
end

View file

@ -0,0 +1,17 @@
require 'rails_helper'
describe Settings::Exports::BookmarksController do
render_views
describe 'GET #index' do
it 'returns a csv of the bookmarked toots' do
user = Fabricate(:user)
user.account.bookmarks.create!(status: Fabricate(:status, uri: 'https://foo.bar/statuses/1312'))
sign_in user, scope: :user
get :index, format: :csv
expect(response.body).to eq "https://foo.bar/statuses/1312\n"
end
end
end

View file

@ -24,10 +24,11 @@ describe StatusesController do
let(:account) { Fabricate(:account) }
let(:status) { Fabricate(:status, account: account) }
context 'when account is suspended' do
let(:account) { Fabricate(:account, suspended: true) }
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
get :show, params: { account_username: account.username, id: status.id }
end
@ -36,6 +37,18 @@ describe StatusesController do
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
get :show, params: { account_username: account.username, id: status.id }
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
context 'when status is a reblog' do
let(:original_account) { Fabricate(:account, domain: 'example.com') }
let(:original_status) { Fabricate(:status, account: original_account, url: 'https://example.com/123') }
@ -676,10 +689,11 @@ describe StatusesController do
let(:account) { Fabricate(:account) }
let(:status) { Fabricate(:status, account: account) }
context 'when account is suspended' do
let(:account) { Fabricate(:account, suspended: true) }
context 'when account is permanently suspended' do
before do
account.suspend!
account.deletion_request.destroy
get :activity, params: { account_username: account.username, id: status.id }
end
@ -688,6 +702,18 @@ describe StatusesController do
end
end
context 'when account is temporarily suspended' do
before do
account.suspend!
get :activity, params: { account_username: account.username, id: status.id }
end
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
context 'when status is public' do
pending
end

View file

@ -12,7 +12,7 @@ describe WellKnown::HostMetaController, type: :controller do
expect(response.body).to eq <<XML
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Link rel="lrdd" type="application/xrd+xml" template="https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}"/>
<Link rel="lrdd" template="https://cb6e6126.ngrok.io/.well-known/webfinger?resource={uri}"/>
</XRD>
XML
end

View file

@ -4,95 +4,134 @@ describe WellKnown::WebfingerController, type: :controller do
render_views
describe 'GET #show' do
let(:alice) do
Fabricate(:account, username: 'alice')
end
before do
alice.private_key = <<-PEM
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDHgPoPJlrfMZrVcuF39UbVssa8r4ObLP3dYl9Y17Mgp5K4mSYD
R/Y2ag58tSi6ar2zM3Ze3QYsNfTq0NqN1g89eAu0MbSjWqpOsgntRPJiFuj3hai2
X2Im8TBrkiM/UyfTRgn8q8WvMoKbXk8Lu6nqv420eyqhhLxfUoCpxuem1QIDAQAB
AoGBAIKsOh2eM7spVI8mdgQKheEG/iEsnPkQ2R8ehfE9JzjmSbXbqghQJDaz9NU+
G3Uu4R31QT0VbCudE9SSA/UPFl82GeQG4QLjrSE+PSjSkuslgSXelJHfAJ+ycGax
ajtPyiQD0e4c2loagHNHPjqK9OhHx9mFnZWmoagjlZ+mQGEpAkEA8GtqfS65IaRQ
uVhMzpp25rF1RWOwaaa+vBPkd7pGdJEQGFWkaR/a9UkU+2C4ZxGBkJDP9FApKVQI
RANEwN3/hwJBANRuw5+es6BgBv4PD387IJvuruW2oUtYP+Lb2Z5k77J13hZTr0db
Oo9j1UbbR0/4g+vAcsDl4JD9c/9LrGYEpcMCQBon9Yvs+2M3lziy7JhFoc3zXIjS
Ea1M4M9hcqe78lJYPeIH3z04o/+vlcLLgQRlmSz7NESmO/QtGkEcAezhuh0CQHji
pzO4LeO/gXslut3eGcpiYuiZquOjToecMBRwv+5AIKd367Che4uJdh6iPcyGURvh
IewfZFFdyZqnx20ui90CQQC1W2rK5Y30wAunOtSLVA30TLK/tKrTppMC3corjKlB
FTX8IvYBNTbpEttc1VCf/0ccnNpfb0CrFNSPWxRj7t7D
-----END RSA PRIVATE KEY-----
PEM
alice.public_key = <<-PEM
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHgPoPJlrfMZrVcuF39UbVssa8
r4ObLP3dYl9Y17Mgp5K4mSYDR/Y2ag58tSi6ar2zM3Ze3QYsNfTq0NqN1g89eAu0
MbSjWqpOsgntRPJiFuj3hai2X2Im8TBrkiM/UyfTRgn8q8WvMoKbXk8Lu6nqv420
eyqhhLxfUoCpxuem1QIDAQAB
-----END PUBLIC KEY-----
PEM
alice.save!
end
let(:alternate_domains) { [] }
let(:alice) { Fabricate(:account, username: 'alice') }
let(:resource) { nil }
around(:each) do |example|
before = Rails.configuration.x.alternate_domains
tmp = Rails.configuration.x.alternate_domains
Rails.configuration.x.alternate_domains = alternate_domains
example.run
Rails.configuration.x.alternate_domains = before
Rails.configuration.x.alternate_domains = tmp
end
it 'returns JSON when account can be found' do
get :show, params: { resource: alice.to_webfinger_s }, format: :json
json = body_as_json
expect(response).to have_http_status(200)
expect(response.content_type).to eq 'application/jrd+json'
expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io'
expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')
subject do
get :show, params: { resource: resource }, format: :json
end
it 'returns http not found when account cannot be found' do
get :show, params: { resource: 'acct:not@existing.com' }, format: :json
shared_examples 'a successful response' do
it 'returns http success' do
expect(response).to have_http_status(200)
end
expect(response).to have_http_status(:not_found)
it 'returns application/jrd+json' do
expect(response.content_type).to eq 'application/jrd+json'
end
it 'returns links for the account' do
json = body_as_json
expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io'
expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')
end
end
it 'returns JSON when account can be found with alternate domains' do
Rails.configuration.x.alternate_domains = ['foo.org']
username, = alice.to_webfinger_s.split('@')
context 'when an account exists' do
let(:resource) { alice.to_webfinger_s }
get :show, params: { resource: "#{username}@foo.org" }, format: :json
before do
subject
end
json = body_as_json
expect(response).to have_http_status(200)
expect(response.content_type).to eq 'application/jrd+json'
expect(json[:subject]).to eq 'acct:alice@cb6e6126.ngrok.io'
expect(json[:aliases]).to include('https://cb6e6126.ngrok.io/@alice', 'https://cb6e6126.ngrok.io/users/alice')
it_behaves_like 'a successful response'
end
it 'returns http not found when account can not be found with alternate domains' do
Rails.configuration.x.alternate_domains = ['foo.org']
username, = alice.to_webfinger_s.split('@')
context 'when an account is temporarily suspended' do
let(:resource) { alice.to_webfinger_s }
get :show, params: { resource: "#{username}@bar.org" }, format: :json
before do
alice.suspend!
subject
end
expect(response).to have_http_status(:not_found)
it_behaves_like 'a successful response'
end
it 'returns http bad request when not given a resource parameter' do
get :show, params: { }, format: :json
expect(response).to have_http_status(:bad_request)
context 'when an account is permanently suspended or deleted' do
let(:resource) { alice.to_webfinger_s }
before do
alice.suspend!
alice.deletion_request.destroy
subject
end
it 'returns http gone' do
expect(response).to have_http_status(410)
end
end
it 'returns http bad request when given a nonsense parameter' do
get :show, params: { resource: 'df/:dfkj' }
expect(response).to have_http_status(:bad_request)
context 'when an account is not found' do
let(:resource) { 'acct:not@existing.com' }
before do
subject
end
it 'returns http not found' do
expect(response).to have_http_status(404)
end
end
context 'with an alternate domain' do
let(:alternate_domains) { ['foo.org'] }
before do
subject
end
context 'when an account exists' do
let(:resource) do
username, = alice.to_webfinger_s.split('@')
"#{username}@foo.org"
end
it_behaves_like 'a successful response'
end
context 'when the domain is wrong' do
let(:resource) do
username, = alice.to_webfinger_s.split('@')
"#{username}@bar.org"
end
it 'returns http not found' do
expect(response).to have_http_status(404)
end
end
end
context 'with no resource parameter' do
let(:resource) { nil }
before do
subject
end
it 'returns http bad request' do
expect(response).to have_http_status(400)
end
end
context 'with a nonsense parameter' do
let(:resource) { 'df/:dfkj' }
before do
subject
end
it 'returns http bad request' do
expect(response).to have_http_status(400)
end
end
end
end