Remove Salmon and PubSubHubbub (#11205)
* Remove Salmon and PubSubHubbub endpoints * Add error when trying to follow OStatus accounts * Fix new accounts not being created in ResolveAccountService
This commit is contained in:
parent
c07cca4727
commit
23aeef52cc
102 changed files with 70 additions and 3569 deletions
|
@ -75,44 +75,6 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'POST #subscribe' do
|
||||
subject { post :subscribe, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: admin) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:admin) { true }
|
||||
|
||||
it { is_expected.to redirect_to admin_account_path(account.id) }
|
||||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:admin) { false }
|
||||
|
||||
it { is_expected.to have_http_status :forbidden }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #unsubscribe' do
|
||||
subject { post :unsubscribe, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: admin) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:admin) { true }
|
||||
|
||||
it { is_expected.to redirect_to admin_account_path(account.id) }
|
||||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:admin) { false }
|
||||
|
||||
it { is_expected.to have_http_status :forbidden }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #memorialize' do
|
||||
subject { post :memorialize, params: { id: account.id } }
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Admin::SubscriptionsController, type: :controller do
|
||||
render_views
|
||||
|
||||
describe 'GET #index' do
|
||||
around do |example|
|
||||
default_per_page = Subscription.default_per_page
|
||||
Subscription.paginates_per 1
|
||||
example.run
|
||||
Subscription.paginates_per default_per_page
|
||||
end
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true), scope: :user
|
||||
end
|
||||
|
||||
it 'renders subscriptions' do
|
||||
Fabricate(:subscription)
|
||||
specified = Fabricate(:subscription)
|
||||
|
||||
get :index
|
||||
|
||||
subscriptions = assigns(:subscriptions)
|
||||
expect(subscriptions.count).to eq 1
|
||||
expect(subscriptions[0]).to eq specified
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,59 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::PushController, type: :controller do
|
||||
describe 'POST #update' do
|
||||
context 'with hub.mode=subscribe' do
|
||||
it 'creates a subscription' do
|
||||
service = double(call: ['', 202])
|
||||
allow(Pubsubhubbub::SubscribeService).to receive(:new).and_return(service)
|
||||
account = Fabricate(:account)
|
||||
account_topic_url = "https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom"
|
||||
post :update, params: {
|
||||
'hub.mode' => 'subscribe',
|
||||
'hub.topic' => account_topic_url,
|
||||
'hub.callback' => 'https://callback.host/api',
|
||||
'hub.lease_seconds' => '3600',
|
||||
'hub.secret' => 'as1234df',
|
||||
}
|
||||
|
||||
expect(service).to have_received(:call).with(
|
||||
account,
|
||||
'https://callback.host/api',
|
||||
'as1234df',
|
||||
'3600',
|
||||
nil
|
||||
)
|
||||
expect(response).to have_http_status(202)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with hub.mode=unsubscribe' do
|
||||
it 'unsubscribes the account' do
|
||||
service = double(call: ['', 202])
|
||||
allow(Pubsubhubbub::UnsubscribeService).to receive(:new).and_return(service)
|
||||
account = Fabricate(:account)
|
||||
account_topic_url = "https://#{Rails.configuration.x.local_domain}/users/#{account.username}.atom"
|
||||
post :update, params: {
|
||||
'hub.mode' => 'unsubscribe',
|
||||
'hub.topic' => account_topic_url,
|
||||
'hub.callback' => 'https://callback.host/api',
|
||||
}
|
||||
|
||||
expect(service).to have_received(:call).with(
|
||||
account,
|
||||
'https://callback.host/api',
|
||||
)
|
||||
expect(response).to have_http_status(202)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with unknown mode' do
|
||||
it 'returns an unknown mode error' do
|
||||
post :update, params: { 'hub.mode' => 'fake' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response.body).to match(/Unknown mode/)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,65 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::SalmonController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:account) { Fabricate(:user, account: Fabricate(:account, username: 'catsrgr8')).account }
|
||||
|
||||
before do
|
||||
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
|
||||
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
|
||||
stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
|
||||
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
|
||||
end
|
||||
|
||||
describe 'POST #update' do
|
||||
context 'with valid post data' do
|
||||
before do
|
||||
post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))
|
||||
end
|
||||
|
||||
it 'contains XML in the request body' do
|
||||
expect(request.body.read).to be_a String
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(202)
|
||||
end
|
||||
|
||||
it 'creates remote account' do
|
||||
expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
|
||||
end
|
||||
|
||||
it 'creates status' do
|
||||
expect(Status.find_by(uri: 'tag:quitter.no,2016-03-20:noticeId=1276923:objectType=note')).to_not be_nil
|
||||
end
|
||||
|
||||
it 'creates mention for target account' do
|
||||
expect(account.mentions.count).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'with empty post data' do
|
||||
before do
|
||||
post :update, params: { id: account.id }, body: ''
|
||||
end
|
||||
|
||||
it 'returns http client error' do
|
||||
expect(response).to have_http_status(400)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid post data' do
|
||||
before do
|
||||
service = double(call: false)
|
||||
allow(VerifySalmonService).to receive(:new).and_return(service)
|
||||
|
||||
post :update, params: { id: account.id }, body: File.read(Rails.root.join('spec', 'fixtures', 'salmon', 'mention.xml'))
|
||||
end
|
||||
|
||||
it 'returns http client error' do
|
||||
expect(response).to have_http_status(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,68 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::SubscriptionsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:account) { Fabricate(:account, username: 'gargron', domain: 'quitter.no', remote_url: 'topic_url', secret: 'abc') }
|
||||
|
||||
describe 'GET #show' do
|
||||
context 'with valid subscription' do
|
||||
before do
|
||||
get :show, params: { :id => account.id, 'hub.topic' => 'topic_url', 'hub.challenge' => '456', 'hub.lease_seconds' => "#{86400 * 30}" }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'echoes back the challenge' do
|
||||
expect(response.body).to match '456'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with invalid subscription' do
|
||||
before do
|
||||
expect_any_instance_of(Account).to receive_message_chain(:subscription, :valid?).and_return(false)
|
||||
get :show, params: { :id => account.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #update' do
|
||||
let(:feed) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }
|
||||
|
||||
before do
|
||||
stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
|
||||
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
|
||||
stub_request(:get, "https://quitter.no/notice/1269244").to_return(status: 404)
|
||||
stub_request(:get, "https://quitter.no/notice/1265331").to_return(status: 404)
|
||||
stub_request(:get, "https://community.highlandarrow.com/notice/54411").to_return(status: 404)
|
||||
stub_request(:get, "https://community.highlandarrow.com/notice/53857").to_return(status: 404)
|
||||
stub_request(:get, "https://community.highlandarrow.com/notice/51852").to_return(status: 404)
|
||||
stub_request(:get, "https://social.umeahackerspace.se/notice/424348").to_return(status: 404)
|
||||
stub_request(:get, "https://community.highlandarrow.com/notice/50467").to_return(status: 404)
|
||||
stub_request(:get, "https://quitter.no/notice/1243309").to_return(status: 404)
|
||||
stub_request(:get, "https://quitter.no/user/7477").to_return(status: 404)
|
||||
stub_request(:any, "https://community.highlandarrow.com/user/1").to_return(status: 404)
|
||||
stub_request(:any, "https://social.umeahackerspace.se/user/2").to_return(status: 404)
|
||||
stub_request(:any, "https://gs.kawa-kun.com/user/2").to_return(status: 404)
|
||||
stub_request(:any, "https://mastodon.social/users/Gargron").to_return(status: 404)
|
||||
|
||||
request.env['HTTP_X_HUB_SIGNATURE'] = "sha1=#{OpenSSL::HMAC.hexdigest('sha1', 'abc', feed)}"
|
||||
|
||||
post :update, params: { id: account.id }, body: feed
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates statuses for feed' do
|
||||
expect(account.statuses.count).to_not eq 0
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,51 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Api::V1::FollowsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:follows') }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:doorkeeper_token) { token }
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
before do
|
||||
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
|
||||
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
|
||||
stub_request(:head, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(:status => 405, :body => "", :headers => {})
|
||||
stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
|
||||
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
|
||||
stub_request(:post, "https://quitter.no/main/push/hub").to_return(:status => 200, :body => "", :headers => {})
|
||||
stub_request(:post, "https://quitter.no/main/salmon/user/7477").to_return(:status => 200, :body => "", :headers => {})
|
||||
|
||||
post :create, params: { uri: 'gargron@quitter.no' }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'creates account for remote user' do
|
||||
expect(Account.find_by(username: 'gargron', domain: 'quitter.no')).to_not be_nil
|
||||
end
|
||||
|
||||
it 'creates a follow relation between user and remote user' do
|
||||
expect(user.account.following?(Account.find_by(username: 'gargron', domain: 'quitter.no'))).to be true
|
||||
end
|
||||
|
||||
it 'sends a salmon slap to the remote user' do
|
||||
expect(a_request(:post, "https://quitter.no/main/salmon/user/7477")).to have_been_made
|
||||
end
|
||||
|
||||
it 'subscribes to remote hub' do
|
||||
expect(a_request(:post, "https://quitter.no/main/push/hub")).to have_been_made
|
||||
end
|
||||
|
||||
it 'returns http success if already following, too' do
|
||||
post :create, params: { uri: 'gargron@quitter.no' }
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
2
spec/fixtures/requests/webfinger.txt
vendored
2
spec/fixtures/requests/webfinger.txt
vendored
|
@ -8,4 +8,4 @@ Access-Control-Allow-Origin: *
|
|||
Vary: Accept-Encoding,Cookie
|
||||
Strict-Transport-Security: max-age=31536000; includeSubdomains;
|
||||
|
||||
{"subject":"acct:gargron@quitter.no","aliases":["https:\/\/quitter.no\/user\/7477","https:\/\/quitter.no\/gargron","https:\/\/quitter.no\/index.php\/user\/7477","https:\/\/quitter.no\/index.php\/gargron"],"links":[{"rel":"http:\/\/webfinger.net\/rel\/profile-page","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/gmpg.org\/xfn\/11","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"describedby","type":"application\/rdf+xml","href":"https:\/\/quitter.no\/gargron\/foaf"},{"rel":"http:\/\/apinamespace.org\/atom","type":"application\/atomsvc+xml","href":"https:\/\/quitter.no\/api\/statusnet\/app\/service\/gargron.xml"},{"rel":"http:\/\/apinamespace.org\/twitter","href":"https:\/\/quitter.no\/api\/"},{"rel":"http:\/\/specs.openid.net\/auth\/2.0\/provider","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/schemas.google.com\/g\/2010#updates-from","type":"application\/atom+xml","href":"https:\/\/quitter.no\/api\/statuses\/user_timeline\/7477.atom"},{"rel":"magic-public-key","href":"data:application\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB"},{"rel":"salmon","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-replies","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-mention","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/ostatus.org\/schema\/1.0\/subscribe","template":"https:\/\/quitter.no\/main\/ostatussub?profile={uri}"}]}
|
||||
{"subject":"acct:gargron@quitter.no","aliases":["https:\/\/quitter.no\/user\/7477","https:\/\/quitter.no\/gargron","https:\/\/quitter.no\/index.php\/user\/7477","https:\/\/quitter.no\/index.php\/gargron"],"links":[{"rel":"http:\/\/webfinger.net\/rel\/profile-page","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/gmpg.org\/xfn\/11","type":"text\/html","href":"https:\/\/quitter.no\/gargron"},{"rel":"describedby","type":"application\/rdf+xml","href":"https:\/\/quitter.no\/gargron\/foaf"},{"rel":"http:\/\/apinamespace.org\/atom","type":"application\/atomsvc+xml","href":"https:\/\/quitter.no\/api\/statusnet\/app\/service\/gargron.xml"},{"rel":"http:\/\/apinamespace.org\/twitter","href":"https:\/\/quitter.no\/api\/"},{"rel":"http:\/\/specs.openid.net\/auth\/2.0\/provider","href":"https:\/\/quitter.no\/gargron"},{"rel":"http:\/\/schemas.google.com\/g\/2010#updates-from","type":"application\/atom+xml","href":"https:\/\/quitter.no\/api\/statuses\/user_timeline\/7477.atom"},{"rel":"magic-public-key","href":"data:application\/magic-public-key,RSA.1ZBkHTavLvxH3FzlKv4O6WtlILKRFfNami3_Rcu8EuogtXSYiS-bB6hElZfUCSHbC4uLemOA34PEhz__CDMozax1iI_t8dzjDnh1x0iFSup7pSfW9iXk_WU3Dm74yWWW2jildY41vWgrEstuQ1dJ8vVFfSJ9T_tO4c-T9y8vDI8=.AQAB"},{"rel":"salmon","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-replies","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/salmon-protocol.org\/ns\/salmon-mention","href":"https:\/\/quitter.no\/main\/salmon\/user\/7477"},{"rel":"http:\/\/ostatus.org\/schema\/1.0\/subscribe","template":"https:\/\/quitter.no\/main\/ostatussub?profile={uri}"}]}
|
||||
|
|
|
@ -406,28 +406,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
scope = entry.nodes.find { |node| node.name == 'mastodon:scope' }
|
||||
expect(scope.text).to eq 'public'
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view triggers creation when processed' do
|
||||
remote_account = Account.create!(username: 'username')
|
||||
remote_status = Fabricate(:status, account: remote_account, created_at: '2000-01-01T00:00:00Z')
|
||||
|
||||
entry = OStatus::AtomSerializer.new.entry(remote_status.stream_entry, true)
|
||||
entry.nodes.delete_if { |node| node[:type] == 'application/activity+json' } # Remove ActivityPub link to simplify test
|
||||
xml = OStatus::AtomSerializer.render(entry).gsub('cb6e6126.ngrok.io', 'remote.test')
|
||||
|
||||
remote_status.destroy!
|
||||
remote_account.destroy!
|
||||
|
||||
account = Account.create!(
|
||||
domain: 'remote.test',
|
||||
username: 'username',
|
||||
last_webfingered_at: Time.now.utc
|
||||
)
|
||||
|
||||
ProcessFeedService.new.call(xml, account)
|
||||
|
||||
expect(Status.find_by(uri: "https://remote.test/users/#{remote_status.account.to_param}/statuses/#{remote_status.id}")).to be_instance_of Status
|
||||
end
|
||||
end
|
||||
|
||||
context 'if status is not present' do
|
||||
|
@ -683,24 +661,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
end
|
||||
end
|
||||
|
||||
it 'appends link element for hub' do
|
||||
account = Fabricate(:account, username: 'username')
|
||||
|
||||
feed = OStatus::AtomSerializer.new.feed(account, [])
|
||||
|
||||
link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'hub' }
|
||||
expect(link[:href]).to eq 'https://cb6e6126.ngrok.io/api/push'
|
||||
end
|
||||
|
||||
it 'appends link element for Salmon' do
|
||||
account = Fabricate(:account, username: 'username')
|
||||
|
||||
feed = OStatus::AtomSerializer.new.feed(account, [])
|
||||
|
||||
link = feed.nodes.find { |node| node.name == 'link' && node[:rel] == 'salmon' }
|
||||
expect(link[:href]).to start_with 'https://cb6e6126.ngrok.io/api/salmon/'
|
||||
end
|
||||
|
||||
it 'appends stream entries' do
|
||||
account = Fabricate(:account, username: 'username')
|
||||
status = Fabricate(:status, account: account)
|
||||
|
@ -784,18 +744,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
object = block_salmon.nodes.find { |node| node.name == 'activity:object' }
|
||||
expect(object.id.text).to eq 'https://domain.test/id'
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view triggers block when processed' do
|
||||
block = Fabricate(:block)
|
||||
block_salmon = OStatus::AtomSerializer.new.block_salmon(block)
|
||||
xml = OStatus::AtomSerializer.render(block_salmon)
|
||||
envelope = OStatus2::Salmon.new.pack(xml, block.account.keypair)
|
||||
block.destroy!
|
||||
|
||||
ProcessInteractionService.new.call(envelope, block.target_account)
|
||||
|
||||
expect(block.account.blocking?(block.target_account)).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unblock_salmon' do
|
||||
|
@ -871,17 +819,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
object = unblock_salmon.nodes.find { |node| node.name == 'activity:object' }
|
||||
expect(object.id.text).to eq 'https://domain.test/id'
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view triggers block when processed' do
|
||||
block = Fabricate(:block)
|
||||
unblock_salmon = OStatus::AtomSerializer.new.unblock_salmon(block)
|
||||
xml = OStatus::AtomSerializer.render(unblock_salmon)
|
||||
envelope = OStatus2::Salmon.new.pack(xml, block.account.keypair)
|
||||
|
||||
ProcessInteractionService.new.call(envelope, block.target_account)
|
||||
|
||||
expect { block.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
||||
describe '#favourite_salmon' do
|
||||
|
@ -964,17 +901,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
expect(favourite_salmon.title.text).to eq 'account favourited a status by status_account@remote'
|
||||
expect(favourite_salmon.content.text).to eq 'account favourited a status by status_account@remote'
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view triggers favourite when processed' do
|
||||
favourite = Fabricate(:favourite)
|
||||
favourite_salmon = OStatus::AtomSerializer.new.favourite_salmon(favourite)
|
||||
xml = OStatus::AtomSerializer.render(favourite_salmon)
|
||||
envelope = OStatus2::Salmon.new.pack(xml, favourite.account.keypair)
|
||||
favourite.destroy!
|
||||
|
||||
ProcessInteractionService.new.call(envelope, favourite.status.account)
|
||||
expect(favourite.account.favourited?(favourite.status)).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unfavourite_salmon' do
|
||||
|
@ -1064,16 +990,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
expect(unfavourite_salmon.title.text).to eq 'account no longer favourites a status by status_account@remote'
|
||||
expect(unfavourite_salmon.content.text).to eq 'account no longer favourites a status by status_account@remote'
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view triggers unfavourite when processed' do
|
||||
favourite = Fabricate(:favourite)
|
||||
unfavourite_salmon = OStatus::AtomSerializer.new.unfavourite_salmon(favourite)
|
||||
xml = OStatus::AtomSerializer.render(unfavourite_salmon)
|
||||
envelope = OStatus2::Salmon.new.pack(xml, favourite.account.keypair)
|
||||
|
||||
ProcessInteractionService.new.call(envelope, favourite.status.account)
|
||||
expect { favourite.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
||||
describe '#follow_salmon' do
|
||||
|
@ -1143,18 +1059,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
expect(follow_salmon.title.text).to eq 'account started following target_account@remote'
|
||||
expect(follow_salmon.content.text).to eq 'account started following target_account@remote'
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view triggers follow when processed' do
|
||||
follow = Fabricate(:follow)
|
||||
follow_salmon = OStatus::AtomSerializer.new.follow_salmon(follow)
|
||||
xml = OStatus::AtomSerializer.render(follow_salmon)
|
||||
follow.destroy!
|
||||
envelope = OStatus2::Salmon.new.pack(xml, follow.account.keypair)
|
||||
|
||||
ProcessInteractionService.new.call(envelope, follow.target_account)
|
||||
|
||||
expect(follow.account.following?(follow.target_account)).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#unfollow_salmon' do
|
||||
|
@ -1251,19 +1155,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
object = unfollow_salmon.nodes.find { |node| node.name == 'activity:object' }
|
||||
expect(object.id.text).to eq 'https://domain.test/id'
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view triggers unfollow when processed' do
|
||||
follow = Fabricate(:follow)
|
||||
follow.destroy!
|
||||
unfollow_salmon = OStatus::AtomSerializer.new.unfollow_salmon(follow)
|
||||
xml = OStatus::AtomSerializer.render(unfollow_salmon)
|
||||
follow.account.follow!(follow.target_account)
|
||||
envelope = OStatus2::Salmon.new.pack(xml, follow.account.keypair)
|
||||
|
||||
ProcessInteractionService.new.call(envelope, follow.target_account)
|
||||
|
||||
expect(follow.account.following?(follow.target_account)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#follow_request_salmon' do
|
||||
|
@ -1294,18 +1185,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
follow_request_salmon = serialize(follow_request)
|
||||
expect(follow_request_salmon.title.text).to eq 'account requested to follow target_account@remote'
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view triggers follow request when processed' do
|
||||
follow_request = Fabricate(:follow_request)
|
||||
follow_request_salmon = serialize(follow_request)
|
||||
xml = OStatus::AtomSerializer.render(follow_request_salmon)
|
||||
envelope = OStatus2::Salmon.new.pack(xml, follow_request.account.keypair)
|
||||
follow_request.destroy!
|
||||
|
||||
ProcessInteractionService.new.call(envelope, follow_request.target_account)
|
||||
|
||||
expect(follow_request.account.requested?(follow_request.target_account)).to eq true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1364,18 +1243,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
verb = authorize_follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
|
||||
expect(verb.text).to eq OStatus::TagManager::VERBS[:authorize]
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view creates follow from follow request when processed' do
|
||||
follow_request = Fabricate(:follow_request)
|
||||
authorize_follow_request_salmon = OStatus::AtomSerializer.new.authorize_follow_request_salmon(follow_request)
|
||||
xml = OStatus::AtomSerializer.render(authorize_follow_request_salmon)
|
||||
envelope = OStatus2::Salmon.new.pack(xml, follow_request.target_account.keypair)
|
||||
|
||||
ProcessInteractionService.new.call(envelope, follow_request.account)
|
||||
|
||||
expect(follow_request.account.following?(follow_request.target_account)).to eq true
|
||||
expect { follow_request.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
||||
describe '#reject_follow_request_salmon' do
|
||||
|
@ -1427,18 +1294,6 @@ RSpec.describe OStatus::AtomSerializer do
|
|||
verb = reject_follow_request_salmon.nodes.find { |node| node.name == 'activity:verb' }
|
||||
expect(verb.text).to eq OStatus::TagManager::VERBS[:reject]
|
||||
end
|
||||
|
||||
it 'returns element whose rendered view deletes follow request when processed' do
|
||||
follow_request = Fabricate(:follow_request)
|
||||
reject_follow_request_salmon = OStatus::AtomSerializer.new.reject_follow_request_salmon(follow_request)
|
||||
xml = OStatus::AtomSerializer.render(reject_follow_request_salmon)
|
||||
envelope = OStatus2::Salmon.new.pack(xml, follow_request.target_account.keypair)
|
||||
|
||||
ProcessInteractionService.new.call(envelope, follow_request.account)
|
||||
|
||||
expect(follow_request.account.following?(follow_request.target_account)).to eq false
|
||||
expect { follow_request.reload }.to raise_error ActiveRecord::RecordNotFound
|
||||
end
|
||||
end
|
||||
|
||||
describe '#object' do
|
||||
|
|
|
@ -38,13 +38,6 @@ RSpec.describe AuthorizeFollowService, type: :service do
|
|||
it 'creates follow relation' do
|
||||
expect(bob.following?(sender)).to be true
|
||||
end
|
||||
|
||||
it 'sends a follow request authorization salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:authorize])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'remote ActivityPub' do
|
||||
|
|
|
@ -49,19 +49,6 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
|
|||
expect(Redis.current).to have_received(:publish).with('timeline:public', any_args).at_least(:once)
|
||||
end
|
||||
|
||||
it 'sends PuSH update to PuSH subscribers' do
|
||||
expect(a_request(:post, 'http://example.com/push').with { |req|
|
||||
matches = req.body.match(OStatus::TagManager::VERBS[:delete])
|
||||
}).to have_been_made.at_least_once
|
||||
end
|
||||
|
||||
it 'sends Salmon slap to previously mentioned users' do
|
||||
expect(a_request(:post, "http://example.com/salmon").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:delete])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
|
||||
it 'sends delete activity to followers' do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.at_least_once
|
||||
end
|
||||
|
|
|
@ -28,13 +28,6 @@ RSpec.describe BlockService, type: :service do
|
|||
it 'creates a blocking relation' do
|
||||
expect(sender.blocking?(bob)).to be true
|
||||
end
|
||||
|
||||
it 'sends a block salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:block])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'remote ActivityPub' do
|
||||
|
|
|
@ -30,13 +30,6 @@ RSpec.describe FavouriteService, type: :service do
|
|||
it 'creates a favourite' do
|
||||
expect(status.favourites.first).to_not be_nil
|
||||
end
|
||||
|
||||
it 'sends a salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:favorite])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'remote ActivityPub' do
|
||||
|
|
|
@ -36,36 +36,6 @@ RSpec.describe FetchRemoteAccountService, type: :service do
|
|||
include_examples 'return Account'
|
||||
end
|
||||
|
||||
context 'protocol is :ostatus' do
|
||||
let(:prefetched_body) { xml }
|
||||
let(:protocol) { :ostatus }
|
||||
|
||||
before do
|
||||
stub_request(:get, "https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone").to_return(request_fixture('webfinger-hacker3.txt'))
|
||||
stub_request(:get, "https://kickass.zone/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
|
||||
end
|
||||
|
||||
include_examples 'return Account'
|
||||
|
||||
it 'does not update account information if XML comes from an unverified domain' do
|
||||
feed_xml = <<-XML.squish
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">
|
||||
<author>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||
<uri>http://kickass.zone/users/localhost</uri>
|
||||
<name>localhost</name>
|
||||
<poco:preferredUsername>localhost</poco:preferredUsername>
|
||||
<poco:displayName>Villain!!!</poco:displayName>
|
||||
</author>
|
||||
</feed>
|
||||
XML
|
||||
|
||||
returned_account = described_class.new.call('https://real-fake-domains.com/alice', feed_xml, :ostatus)
|
||||
expect(returned_account.display_name).to_not eq 'Villain!!!'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when prefetched_body is nil' do
|
||||
context 'protocol is :activitypub' do
|
||||
before do
|
||||
|
@ -75,15 +45,5 @@ RSpec.describe FetchRemoteAccountService, type: :service do
|
|||
|
||||
include_examples 'return Account'
|
||||
end
|
||||
|
||||
context 'protocol is :ostatus' do
|
||||
before do
|
||||
stub_request(:get, url).to_return(status: 200, body: xml, headers: { 'Content-Type' => 'application/atom+xml' })
|
||||
stub_request(:get, "https://kickass.zone/.well-known/webfinger?resource=acct:localhost@kickass.zone").to_return(request_fixture('webfinger-hacker3.txt'))
|
||||
stub_request(:get, "https://kickass.zone/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
|
||||
end
|
||||
|
||||
include_examples 'return Account'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -96,74 +96,6 @@ RSpec.describe FollowService, type: :service do
|
|||
end
|
||||
end
|
||||
|
||||
context 'remote OStatus account' do
|
||||
describe 'locked account' do
|
||||
let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, locked: true, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com')).account }
|
||||
|
||||
before do
|
||||
stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
|
||||
subject.call(sender, bob.acct)
|
||||
end
|
||||
|
||||
it 'creates a follow request' do
|
||||
expect(FollowRequest.find_by(account: sender, target_account: bob)).to_not be_nil
|
||||
end
|
||||
|
||||
it 'sends a follow request salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:request_friend])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unlocked account' do
|
||||
let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account }
|
||||
|
||||
before do
|
||||
stub_request(:post, "http://salmon.example.com/").to_return(:status => 200, :body => "", :headers => {})
|
||||
stub_request(:post, "http://hub.example.com/").to_return(status: 202)
|
||||
subject.call(sender, bob.acct)
|
||||
end
|
||||
|
||||
it 'creates a following relation' do
|
||||
expect(sender.following?(bob)).to be true
|
||||
end
|
||||
|
||||
it 'sends a follow salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:follow])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
|
||||
it 'subscribes to PuSH' do
|
||||
expect(a_request(:post, "http://hub.example.com/")).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'already followed account' do
|
||||
let(:bob) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, protocol: :ostatus, username: 'bob', domain: 'example.com', salmon_url: 'http://salmon.example.com', hub_url: 'http://hub.example.com')).account }
|
||||
|
||||
before do
|
||||
sender.follow!(bob)
|
||||
subject.call(sender, bob.acct)
|
||||
end
|
||||
|
||||
it 'keeps a following relation' do
|
||||
expect(sender.following?(bob)).to be true
|
||||
end
|
||||
|
||||
it 'does not send a follow salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/")).not_to have_been_made
|
||||
end
|
||||
|
||||
it 'does not subscribe to PuSH' do
|
||||
expect(a_request(:post, "http://hub.example.com/")).not_to have_been_made
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'remote ActivityPub account' do
|
||||
let(:bob) { Fabricate(:user, account: Fabricate(:account, username: 'bob', domain: 'example.com', protocol: :activitypub, inbox_url: 'http://example.com/inbox')).account }
|
||||
|
||||
|
|
|
@ -3,7 +3,11 @@ require 'rails_helper'
|
|||
RSpec.describe ImportService, type: :service do
|
||||
let!(:account) { Fabricate(:account, locked: false) }
|
||||
let!(:bob) { Fabricate(:account, username: 'bob', locked: false) }
|
||||
let!(:eve) { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false) }
|
||||
let!(:eve) { Fabricate(:account, username: 'eve', domain: 'example.com', locked: false, protocol: :activitypub, inbox_url: 'https://example.com/inbox') }
|
||||
|
||||
before do
|
||||
stub_request(:post, "https://example.com/inbox").to_return(status: 200)
|
||||
end
|
||||
|
||||
context 'import old-style list of muted users' do
|
||||
subject { ImportService.new }
|
||||
|
@ -95,7 +99,8 @@ RSpec.describe ImportService, type: :service do
|
|||
let(:import) { Import.create(account: account, type: 'following', data: csv) }
|
||||
it 'follows the listed accounts, including boosts' do
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(account.following.count).to eq 1
|
||||
expect(account.follow_requests.count).to eq 1
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
end
|
||||
end
|
||||
|
@ -106,7 +111,8 @@ RSpec.describe ImportService, type: :service do
|
|||
it 'follows the listed accounts, including notifications' do
|
||||
account.follow!(bob, reblogs: false)
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(account.following.count).to eq 1
|
||||
expect(account.follow_requests.count).to eq 1
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
end
|
||||
end
|
||||
|
@ -117,7 +123,8 @@ RSpec.describe ImportService, type: :service do
|
|||
it 'mutes the listed accounts, including notifications' do
|
||||
account.follow!(bob, reblogs: false)
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(account.following.count).to eq 1
|
||||
expect(account.follow_requests.count).to eq 1
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
end
|
||||
end
|
||||
|
@ -136,9 +143,10 @@ RSpec.describe ImportService, type: :service do
|
|||
let(:import) { Import.create(account: account, type: 'following', data: csv) }
|
||||
it 'follows the listed accounts, respecting boosts' do
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(account.following.count).to eq 1
|
||||
expect(account.follow_requests.count).to eq 1
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -148,9 +156,10 @@ RSpec.describe ImportService, type: :service do
|
|||
it 'mutes the listed accounts, respecting notifications' do
|
||||
account.follow!(bob, reblogs: true)
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(account.following.count).to eq 1
|
||||
expect(account.follow_requests.count).to eq 1
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -160,9 +169,10 @@ RSpec.describe ImportService, type: :service do
|
|||
it 'mutes the listed accounts, respecting notifications' do
|
||||
account.follow!(bob, reblogs: true)
|
||||
subject.call(import)
|
||||
expect(account.following.count).to eq 2
|
||||
expect(account.following.count).to eq 1
|
||||
expect(account.follow_requests.count).to eq 1
|
||||
expect(Follow.find_by(account: account, target_account: bob).show_reblogs).to be true
|
||||
expect(Follow.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
expect(FollowRequest.find_by(account: account, target_account: eve).show_reblogs).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -144,7 +144,6 @@ RSpec.describe PostStatusService, type: :service do
|
|||
|
||||
it 'gets distributed' do
|
||||
allow(DistributionWorker).to receive(:perform_async)
|
||||
allow(Pubsubhubbub::DistributionWorker).to receive(:perform_async)
|
||||
allow(ActivityPub::DistributionWorker).to receive(:perform_async)
|
||||
|
||||
account = Fabricate(:account)
|
||||
|
@ -152,7 +151,6 @@ RSpec.describe PostStatusService, type: :service do
|
|||
status = subject.call(account, text: "test status update")
|
||||
|
||||
expect(DistributionWorker).to have_received(:perform_async).with(status.id)
|
||||
expect(Pubsubhubbub::DistributionWorker).to have_received(:perform_async).with(status.stream_entry.id)
|
||||
expect(ActivityPub::DistributionWorker).to have_received(:perform_async).with(status.id)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,252 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ProcessFeedService, type: :service do
|
||||
subject { ProcessFeedService.new }
|
||||
|
||||
describe 'processing a feed' do
|
||||
let(:body) { File.read(Rails.root.join('spec', 'fixtures', 'xml', 'mastodon.atom')) }
|
||||
let(:account) { Fabricate(:account, username: 'localhost', domain: 'kickass.zone') }
|
||||
|
||||
before do
|
||||
stub_request(:post, "https://pubsubhubbub.superfeedr.com/").to_return(:status => 200, :body => "", :headers => {})
|
||||
stub_request(:head, "http://kickass.zone/media/2").to_return(:status => 404)
|
||||
stub_request(:head, "http://kickass.zone/media/3").to_return(:status => 404)
|
||||
stub_request(:get, "http://kickass.zone/system/accounts/avatars/000/000/001/large/eris.png").to_return(request_fixture('avatar.txt'))
|
||||
stub_request(:get, "http://kickass.zone/system/media_attachments/files/000/000/002/original/morpheus_linux.jpg?1476059910").to_return(request_fixture('attachment1.txt'))
|
||||
stub_request(:get, "http://kickass.zone/system/media_attachments/files/000/000/003/original/gizmo.jpg?1476060065").to_return(request_fixture('attachment2.txt'))
|
||||
end
|
||||
|
||||
context 'when domain does not reject media' do
|
||||
before do
|
||||
subject.call(body, account)
|
||||
end
|
||||
|
||||
it 'updates remote user\'s account information' do
|
||||
account.reload
|
||||
expect(account.display_name).to eq '::1'
|
||||
expect(account).to have_attached_file(:avatar)
|
||||
expect(account.avatar_file_name).not_to be_nil
|
||||
end
|
||||
|
||||
it 'creates posts' do
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Status')).to_not be_nil
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')).to_not be_nil
|
||||
end
|
||||
|
||||
it 'marks replies as replies' do
|
||||
status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')
|
||||
expect(status.reply?).to be true
|
||||
end
|
||||
|
||||
it 'sets account being replied to when possible' do
|
||||
status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')
|
||||
expect(status.in_reply_to_account_id).to eq status.account_id
|
||||
end
|
||||
|
||||
it 'ignores delete statuses unless they existed before' do
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=3:objectType=Status')).to be_nil
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=12:objectType=Status')).to be_nil
|
||||
end
|
||||
|
||||
it 'does not create statuses for follows' do
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Follow')).to be_nil
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Follow')).to be_nil
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=4:objectType=Follow')).to be_nil
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=7:objectType=Follow')).to be_nil
|
||||
end
|
||||
|
||||
it 'does not create statuses for favourites' do
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Favourite')).to be_nil
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=3:objectType=Favourite')).to be_nil
|
||||
end
|
||||
|
||||
it 'creates posts with media' do
|
||||
status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=14:objectType=Status')
|
||||
|
||||
expect(status).to_not be_nil
|
||||
expect(status.media_attachments.first).to have_attached_file(:file)
|
||||
expect(status.media_attachments.first.image?).to be true
|
||||
expect(status.media_attachments.first.file_file_name).not_to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when domain is set to reject media' do
|
||||
let!(:domain_block) { Fabricate(:domain_block, domain: 'kickass.zone', reject_media: true) }
|
||||
|
||||
before do
|
||||
subject.call(body, account)
|
||||
end
|
||||
|
||||
it 'updates remote user\'s account information' do
|
||||
account.reload
|
||||
expect(account.display_name).to eq '::1'
|
||||
end
|
||||
|
||||
it 'rejects remote user\'s avatar' do
|
||||
account.reload
|
||||
expect(account.display_name).to eq '::1'
|
||||
expect(account.avatar_file_name).to be_nil
|
||||
end
|
||||
|
||||
it 'creates posts' do
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=1:objectType=Status')).to_not be_nil
|
||||
expect(Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=2:objectType=Status')).to_not be_nil
|
||||
end
|
||||
|
||||
it 'creates posts with remote-only media' do
|
||||
status = Status.find_by(uri: 'tag:kickass.zone,2016-10-10:objectId=14:objectType=Status')
|
||||
|
||||
expect(status).to_not be_nil
|
||||
expect(status.media_attachments.first.file_file_name).to be_nil
|
||||
expect(status.media_attachments.first.unknown?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not accept tampered reblogs' do
|
||||
good_actor = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
|
||||
|
||||
real_body = <<XML
|
||||
<?xml version="1.0"?>
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
|
||||
<id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
|
||||
<published>2017-04-27T13:49:25Z</published>
|
||||
<updated>2017-04-27T13:49:25Z</updated>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
|
||||
<author>
|
||||
<id>https://overwatch.com/users/tracer</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||
<uri>https://overwatch.com/users/tracer</uri>
|
||||
<name>tracer</name>
|
||||
</author>
|
||||
<content type="html">Overwatch rocks</content>
|
||||
</entry>
|
||||
XML
|
||||
|
||||
stub_request(:get, 'https://overwatch.com/users/tracer/updates/1').to_return(status: 200, body: real_body, headers: { 'Content-Type' => 'application/atom+xml' })
|
||||
|
||||
bad_actor = Fabricate(:account, username: 'sombra', domain: 'talon.xyz')
|
||||
|
||||
body = <<XML
|
||||
<?xml version="1.0"?>
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
|
||||
<id>tag:talon.xyz,2017-04-27:objectId=4467137:objectType=Status</id>
|
||||
<published>2017-04-27T13:49:25Z</published>
|
||||
<updated>2017-04-27T13:49:25Z</updated>
|
||||
<author>
|
||||
<id>https://talon.xyz/users/sombra</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||
<uri>https://talon.xyz/users/sombra</uri>
|
||||
<name>sombra</name>
|
||||
</author>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
|
||||
<content type="html">Overwatch SUCKS AHAHA</content>
|
||||
<activity:object>
|
||||
<id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
|
||||
<author>
|
||||
<id>https://overwatch.com/users/tracer</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||
<uri>https://overwatch.com/users/tracer</uri>
|
||||
<name>tracer</name>
|
||||
</author>
|
||||
<content type="html">Overwatch SUCKS AHAHA</content>
|
||||
<link rel="alternate" type="text/html" href="https://overwatch.com/users/tracer/updates/1" />
|
||||
</activity:object>
|
||||
</entry>
|
||||
XML
|
||||
created_statuses = subject.call(body, bad_actor)
|
||||
|
||||
expect(created_statuses.first.reblog?).to be true
|
||||
expect(created_statuses.first.account_id).to eq bad_actor.id
|
||||
expect(created_statuses.first.reblog.account_id).to eq good_actor.id
|
||||
expect(created_statuses.first.reblog.text).to eq 'Overwatch rocks'
|
||||
end
|
||||
|
||||
it 'ignores reblogs if it failed to retrieve reblogged statuses' do
|
||||
stub_request(:get, 'https://overwatch.com/users/tracer/updates/1').to_return(status: 404)
|
||||
|
||||
actor = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
|
||||
|
||||
body = <<XML
|
||||
<?xml version="1.0"?>
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
|
||||
<id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
|
||||
<published>2017-04-27T13:49:25Z</published>
|
||||
<updated>2017-04-27T13:49:25Z</updated>
|
||||
<author>
|
||||
<id>https://overwatch.com/users/tracer</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||
<uri>https://overwatch.com/users/tracer</uri>
|
||||
<name>tracer</name>
|
||||
</author>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/activity</activity:object-type>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/share</activity:verb>
|
||||
<content type="html">Overwatch rocks</content>
|
||||
<activity:object>
|
||||
<id>tag:overwatch.com,2017-04-27:objectId=4467137:objectType=Status</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
|
||||
<author>
|
||||
<id>https://overwatch.com/users/tracer</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||
<uri>https://overwatch.com/users/tracer</uri>
|
||||
<name>tracer</name>
|
||||
</author>
|
||||
<content type="html">Overwatch rocks</content>
|
||||
<link rel="alternate" type="text/html" href="https://overwatch.com/users/tracer/updates/1" />
|
||||
</activity:object>
|
||||
XML
|
||||
|
||||
created_statuses = subject.call(body, actor)
|
||||
|
||||
expect(created_statuses).to eq []
|
||||
end
|
||||
|
||||
it 'ignores statuses with an out-of-order delete' do
|
||||
sender = Fabricate(:account, username: 'tracer', domain: 'overwatch.com')
|
||||
|
||||
delete_body = <<XML
|
||||
<?xml version="1.0"?>
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
|
||||
<id>tag:overwatch.com,2017-04-27:objectId=4487555:objectType=Status</id>
|
||||
<published>2017-04-27T13:49:25Z</published>
|
||||
<updated>2017-04-27T13:49:25Z</updated>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/delete</activity:verb>
|
||||
<author>
|
||||
<id>https://overwatch.com/users/tracer</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||
<uri>https://overwatch.com/users/tracer</uri>
|
||||
<name>tracer</name>
|
||||
</author>
|
||||
</entry>
|
||||
XML
|
||||
|
||||
status_body = <<XML
|
||||
<?xml version="1.0"?>
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:mastodon="http://mastodon.social/schema/1.0">
|
||||
<id>tag:overwatch.com,2017-04-27:objectId=4487555:objectType=Status</id>
|
||||
<published>2017-04-27T13:49:25Z</published>
|
||||
<updated>2017-04-27T13:49:25Z</updated>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
|
||||
<author>
|
||||
<id>https://overwatch.com/users/tracer</id>
|
||||
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
||||
<uri>https://overwatch.com/users/tracer</uri>
|
||||
<name>tracer</name>
|
||||
</author>
|
||||
<content type="html">Overwatch rocks</content>
|
||||
</entry>
|
||||
XML
|
||||
|
||||
subject.call(delete_body, sender)
|
||||
created_statuses = subject.call(status_body, sender)
|
||||
|
||||
expect(created_statuses).to be_empty
|
||||
end
|
||||
end
|
|
@ -1,151 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ProcessInteractionService, type: :service do
|
||||
let(:receiver) { Fabricate(:user, email: 'alice@example.com', account: Fabricate(:account, username: 'alice')).account }
|
||||
let(:sender) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account }
|
||||
let(:remote_sender) { Fabricate(:account, username: 'carol', domain: 'localdomain.com', uri: 'https://webdomain.com/users/carol') }
|
||||
|
||||
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
|
||||
before do
|
||||
receiver.update(locked: true)
|
||||
|
||||
payload = <<XML
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
|
||||
<author>
|
||||
<name>bob</name>
|
||||
<uri>https://cb6e6126.ngrok.io/users/bob</uri>
|
||||
</author>
|
||||
|
||||
<id>someIdHere</id>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/request-friend</activity:verb>
|
||||
</entry>
|
||||
XML
|
||||
|
||||
envelope = OStatus2::Salmon.new.pack(payload, sender.keypair)
|
||||
subject.call(envelope, receiver)
|
||||
end
|
||||
|
||||
it 'creates a record' do
|
||||
expect(FollowRequest.find_by(account: sender, target_account: receiver)).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'follow request slap from known remote user identified by email' do
|
||||
before do
|
||||
receiver.update(locked: true)
|
||||
# Copy already-generated key
|
||||
remote_sender.update(private_key: sender.private_key, public_key: remote_sender.public_key)
|
||||
|
||||
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>someIdHere</id>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/request-friend</activity:verb>
|
||||
</entry>
|
||||
XML
|
||||
|
||||
envelope = OStatus2::Salmon.new.pack(payload, remote_sender.keypair)
|
||||
subject.call(envelope, receiver)
|
||||
end
|
||||
|
||||
it 'creates a record' do
|
||||
expect(FollowRequest.find_by(account: remote_sender, target_account: receiver)).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'follow request authorization slap' do
|
||||
before do
|
||||
receiver.update(locked: true)
|
||||
FollowRequest.create(account: sender, target_account: receiver)
|
||||
|
||||
payload = <<XML
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
|
||||
<author>
|
||||
<name>alice</name>
|
||||
<uri>https://cb6e6126.ngrok.io/users/alice</uri>
|
||||
</author>
|
||||
|
||||
<id>someIdHere</id>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/authorize</activity:verb>
|
||||
</entry>
|
||||
XML
|
||||
|
||||
envelope = OStatus2::Salmon.new.pack(payload, receiver.keypair)
|
||||
subject.call(envelope, sender)
|
||||
end
|
||||
|
||||
it 'creates a follow relationship' do
|
||||
expect(Follow.find_by(account: sender, target_account: receiver)).to_not be_nil
|
||||
end
|
||||
|
||||
it 'removes the follow request' do
|
||||
expect(FollowRequest.find_by(account: sender, target_account: receiver)).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe 'follow request rejection slap' do
|
||||
before do
|
||||
receiver.update(locked: true)
|
||||
FollowRequest.create(account: sender, target_account: receiver)
|
||||
|
||||
payload = <<XML
|
||||
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:activity="http://activitystrea.ms/spec/1.0/">
|
||||
<author>
|
||||
<name>alice</name>
|
||||
<uri>https://cb6e6126.ngrok.io/users/alice</uri>
|
||||
</author>
|
||||
|
||||
<id>someIdHere</id>
|
||||
<activity:verb>http://activitystrea.ms/schema/1.0/reject</activity:verb>
|
||||
</entry>
|
||||
XML
|
||||
|
||||
envelope = OStatus2::Salmon.new.pack(payload, receiver.keypair)
|
||||
subject.call(envelope, sender)
|
||||
end
|
||||
|
||||
it 'does not create a follow relationship' do
|
||||
expect(Follow.find_by(account: sender, target_account: receiver)).to be_nil
|
||||
end
|
||||
|
||||
it 'removes the follow request' do
|
||||
expect(FollowRequest.find_by(account: sender, target_account: receiver)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,10 +18,6 @@ RSpec.describe ProcessMentionsService, type: :service do
|
|||
it 'creates a mention' do
|
||||
expect(remote_user.mentions.where(status: status).count).to eq 1
|
||||
end
|
||||
|
||||
it 'posts to remote user\'s Salmon end point' do
|
||||
expect(a_request(:post, remote_user.salmon_url)).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
context 'OStatus with private toot' do
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Pubsubhubbub::SubscribeService, type: :service do
|
||||
describe '#call' do
|
||||
subject { described_class.new }
|
||||
let(:user_account) { Fabricate(:account) }
|
||||
|
||||
context 'with a nil account' do
|
||||
it 'returns the invalid topic status results' do
|
||||
result = service_call(account: nil)
|
||||
|
||||
expect(result).to eq invalid_topic_status
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an invalid callback url' do
|
||||
it 'returns invalid callback status when callback is blank' do
|
||||
result = service_call(callback: '')
|
||||
|
||||
expect(result).to eq invalid_callback_status
|
||||
end
|
||||
it 'returns invalid callback status when callback is not a URI' do
|
||||
result = service_call(callback: 'invalid-hostname')
|
||||
|
||||
expect(result).to eq invalid_callback_status
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a blocked domain in the callback' do
|
||||
it 'returns callback not allowed' do
|
||||
Fabricate(:domain_block, domain: 'test.host', severity: :suspend)
|
||||
result = service_call(callback: 'https://test.host/api')
|
||||
|
||||
expect(result).to eq not_allowed_callback_status
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a valid account and callback' do
|
||||
it 'returns success status and confirms subscription' do
|
||||
allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)
|
||||
subscription = Fabricate(:subscription, account: user_account)
|
||||
|
||||
result = service_call(callback: subscription.callback_url)
|
||||
expect(result).to eq success_status
|
||||
expect(Pubsubhubbub::ConfirmationWorker).to have_received(:perform_async).with(subscription.id, 'subscribe', 'asdf', 3600)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def service_call(account: user_account, callback: 'https://callback.host', secret: 'asdf', lease_seconds: 3600)
|
||||
subject.call(account, callback, secret, lease_seconds)
|
||||
end
|
||||
|
||||
def invalid_topic_status
|
||||
['Invalid topic URL', 422]
|
||||
end
|
||||
|
||||
def invalid_callback_status
|
||||
['Invalid callback URL', 422]
|
||||
end
|
||||
|
||||
def not_allowed_callback_status
|
||||
['Callback URL not allowed', 403]
|
||||
end
|
||||
|
||||
def success_status
|
||||
['', 202]
|
||||
end
|
||||
end
|
|
@ -1,46 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Pubsubhubbub::UnsubscribeService, type: :service do
|
||||
describe '#call' do
|
||||
subject { described_class.new }
|
||||
|
||||
context 'with a nil account' do
|
||||
it 'returns an invalid topic status' do
|
||||
result = subject.call(nil, 'callback.host')
|
||||
|
||||
expect(result).to eq invalid_topic_status
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a valid account' do
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
it 'returns a valid topic status and does not run confirm when no subscription' do
|
||||
allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)
|
||||
result = subject.call(account, 'callback.host')
|
||||
|
||||
expect(result).to eq valid_topic_status
|
||||
expect(Pubsubhubbub::ConfirmationWorker).not_to have_received(:perform_async)
|
||||
end
|
||||
|
||||
it 'returns a valid topic status and does run confirm when there is a subscription' do
|
||||
subscription = Fabricate(:subscription, account: account, callback_url: 'callback.host')
|
||||
allow(Pubsubhubbub::ConfirmationWorker).to receive(:perform_async).and_return(nil)
|
||||
result = subject.call(account, 'callback.host')
|
||||
|
||||
expect(result).to eq valid_topic_status
|
||||
expect(Pubsubhubbub::ConfirmationWorker).to have_received(:perform_async).with(subscription.id, 'unsubscribe')
|
||||
end
|
||||
end
|
||||
|
||||
def invalid_topic_status
|
||||
['Invalid topic URL', 422]
|
||||
end
|
||||
|
||||
def valid_topic_status
|
||||
['', 202]
|
||||
end
|
||||
end
|
||||
end
|
|
@ -46,10 +46,6 @@ RSpec.describe ReblogService, type: :service do
|
|||
it 'creates a reblog' do
|
||||
expect(status.reblogs.count).to eq 1
|
||||
end
|
||||
|
||||
it 'sends a Salmon slap for a remote reblog' do
|
||||
expect(a_request(:post, 'http://salmon.example.com')).to have_been_made
|
||||
end
|
||||
end
|
||||
|
||||
context 'ActivityPub' do
|
||||
|
|
|
@ -38,13 +38,6 @@ RSpec.describe RejectFollowService, type: :service do
|
|||
it 'does not create follow relation' do
|
||||
expect(bob.following?(sender)).to be false
|
||||
end
|
||||
|
||||
it 'sends a follow request rejection salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:reject])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'remote ActivityPub' do
|
||||
|
|
|
@ -32,23 +32,10 @@ RSpec.describe RemoveStatusService, type: :service do
|
|||
expect(HomeFeed.new(jeff).get(10)).to_not include(@status.id)
|
||||
end
|
||||
|
||||
it 'sends PuSH update to PuSH subscribers' do
|
||||
expect(a_request(:post, 'http://example.com/push').with { |req|
|
||||
req.body.match(OStatus::TagManager::VERBS[:delete])
|
||||
}).to have_been_made
|
||||
end
|
||||
|
||||
it 'sends delete activity to followers' do
|
||||
expect(a_request(:post, 'http://example.com/inbox')).to have_been_made.twice
|
||||
end
|
||||
|
||||
it 'sends Salmon slap to previously mentioned users' do
|
||||
expect(a_request(:post, "http://example.com/salmon").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:delete])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
|
||||
it 'sends delete activity to rebloggers' do
|
||||
expect(a_request(:post, 'http://example2.com/inbox')).to have_been_made
|
||||
end
|
||||
|
|
|
@ -6,19 +6,13 @@ RSpec.describe ResolveAccountService, type: :service do
|
|||
before do
|
||||
stub_request(:get, "https://quitter.no/.well-known/host-meta").to_return(request_fixture('.host-meta.txt'))
|
||||
stub_request(:get, "https://example.com/.well-known/webfinger?resource=acct:catsrgr8@example.com").to_return(status: 404)
|
||||
stub_request(:get, "https://redirected.com/.well-known/host-meta").to_return(request_fixture('redirected.host-meta.txt'))
|
||||
stub_request(:get, "https://example.com/.well-known/host-meta").to_return(status: 404)
|
||||
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:gargron@quitter.no").to_return(request_fixture('webfinger.txt'))
|
||||
stub_request(:get, "https://redirected.com/.well-known/webfinger?resource=acct:gargron@redirected.com").to_return(request_fixture('webfinger.txt'))
|
||||
stub_request(:get, "https://redirected.com/.well-known/webfinger?resource=acct:hacker1@redirected.com").to_return(request_fixture('webfinger-hacker1.txt'))
|
||||
stub_request(:get, "https://redirected.com/.well-known/webfinger?resource=acct:hacker2@redirected.com").to_return(request_fixture('webfinger-hacker2.txt'))
|
||||
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no").to_return(status: 404)
|
||||
stub_request(:get, "https://quitter.no/api/statuses/user_timeline/7477.atom").to_return(request_fixture('feed.txt'))
|
||||
stub_request(:get, "https://quitter.no/avatar/7477-300-20160211190340.png").to_return(request_fixture('avatar.txt'))
|
||||
stub_request(:get, "https://localdomain.com/.well-known/host-meta").to_return(request_fixture('localdomain-hostmeta.txt'))
|
||||
stub_request(:get, "https://localdomain.com/.well-known/webfinger?resource=acct:foo@localdomain.com").to_return(status: 404)
|
||||
stub_request(:get, "https://webdomain.com/.well-known/webfinger?resource=acct:foo@localdomain.com").to_return(request_fixture('localdomain-webfinger.txt'))
|
||||
stub_request(:get, "https://webdomain.com/users/foo.atom").to_return(request_fixture('localdomain-feed.txt'))
|
||||
stub_request(:get, "https://quitter.no/.well-known/webfinger?resource=acct:catsrgr8@quitter.no").to_return(status: 404)
|
||||
stub_request(:get, "https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com").to_return(request_fixture('activitypub-webfinger.txt'))
|
||||
stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor.txt'))
|
||||
stub_request(:get, "https://ap.example.com/users/foo.atom").to_return(request_fixture('activitypub-feed.txt'))
|
||||
stub_request(:get, %r{https://ap.example.com/users/foo/\w+}).to_return(status: 404)
|
||||
end
|
||||
|
||||
it 'raises error if no such user can be resolved via webfinger' do
|
||||
|
@ -29,74 +23,7 @@ RSpec.describe ResolveAccountService, type: :service do
|
|||
expect(subject.call('catsrgr8@example.com')).to be_nil
|
||||
end
|
||||
|
||||
it 'prevents hijacking existing accounts' do
|
||||
account = subject.call('hacker1@redirected.com')
|
||||
expect(account.salmon_url).to_not eq 'https://hacker.com/main/salmon/user/7477'
|
||||
end
|
||||
|
||||
it 'prevents hijacking inexisting accounts' do
|
||||
expect(subject.call('hacker2@redirected.com')).to be_nil
|
||||
end
|
||||
|
||||
context 'with an OStatus account' do
|
||||
it 'returns an already existing remote account' do
|
||||
old_account = Fabricate(:account, username: 'gargron', domain: 'quitter.no')
|
||||
returned_account = subject.call('gargron@quitter.no')
|
||||
|
||||
expect(old_account.id).to eq returned_account.id
|
||||
end
|
||||
|
||||
it 'returns a new remote account' do
|
||||
account = subject.call('gargron@quitter.no')
|
||||
|
||||
expect(account.username).to eq 'gargron'
|
||||
expect(account.domain).to eq 'quitter.no'
|
||||
expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'
|
||||
end
|
||||
|
||||
it 'follows a legitimate account redirection' do
|
||||
account = subject.call('gargron@redirected.com')
|
||||
|
||||
expect(account.username).to eq 'gargron'
|
||||
expect(account.domain).to eq 'quitter.no'
|
||||
expect(account.remote_url).to eq 'https://quitter.no/api/statuses/user_timeline/7477.atom'
|
||||
end
|
||||
|
||||
it 'returns a new remote account' do
|
||||
account = subject.call('foo@localdomain.com')
|
||||
|
||||
expect(account.username).to eq 'foo'
|
||||
expect(account.domain).to eq 'localdomain.com'
|
||||
expect(account.remote_url).to eq 'https://webdomain.com/users/foo.atom'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an ActivityPub account' do
|
||||
before do
|
||||
stub_request(:get, "https://ap.example.com/.well-known/webfinger?resource=acct:foo@ap.example.com").to_return(request_fixture('activitypub-webfinger.txt'))
|
||||
stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor.txt'))
|
||||
stub_request(:get, "https://ap.example.com/users/foo.atom").to_return(request_fixture('activitypub-feed.txt'))
|
||||
stub_request(:get, %r{https://ap.example.com/users/foo/\w+}).to_return(status: 404)
|
||||
end
|
||||
|
||||
it 'fallback to OStatus if actor json could not be fetched' do
|
||||
stub_request(:get, "https://ap.example.com/users/foo").to_return(status: 404)
|
||||
|
||||
account = subject.call('foo@ap.example.com')
|
||||
|
||||
expect(account.ostatus?).to eq true
|
||||
expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'
|
||||
end
|
||||
|
||||
it 'fallback to OStatus if actor json did not have inbox_url' do
|
||||
stub_request(:get, "https://ap.example.com/users/foo").to_return(request_fixture('activitypub-actor-noinbox.txt'))
|
||||
|
||||
account = subject.call('foo@ap.example.com')
|
||||
|
||||
expect(account.ostatus?).to eq true
|
||||
expect(account.remote_url).to eq 'https://ap.example.com/users/foo.atom'
|
||||
end
|
||||
|
||||
it 'returns new remote account' do
|
||||
account = subject.call('foo@ap.example.com')
|
||||
|
||||
|
@ -124,13 +51,14 @@ RSpec.describe ResolveAccountService, type: :service do
|
|||
it 'processes one remote account at a time using locks' do
|
||||
wait_for_start = true
|
||||
fail_occurred = false
|
||||
return_values = []
|
||||
return_values = Concurrent::Array.new
|
||||
|
||||
threads = Array.new(5) do
|
||||
Thread.new do
|
||||
true while wait_for_start
|
||||
|
||||
begin
|
||||
return_values << described_class.new.call('foo@localdomain.com')
|
||||
return_values << described_class.new.call('foo@ap.example.com')
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
fail_occurred = true
|
||||
end
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SendInteractionService, type: :service do
|
||||
subject { SendInteractionService.new }
|
||||
|
||||
it 'sends an XML envelope to the Salmon end point of remote user'
|
||||
end
|
|
@ -1,43 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe SubscribeService, type: :service do
|
||||
let(:account) { Fabricate(:account, username: 'bob', domain: 'example.com', hub_url: 'http://hub.example.com') }
|
||||
subject { SubscribeService.new }
|
||||
|
||||
it 'sends subscription request to PuSH hub' do
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 202)
|
||||
subject.call(account)
|
||||
expect(a_request(:post, 'http://hub.example.com/')).to have_been_made.once
|
||||
end
|
||||
|
||||
it 'generates and keeps PuSH secret on successful call' do
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 202)
|
||||
subject.call(account)
|
||||
expect(account.secret).to_not be_blank
|
||||
end
|
||||
|
||||
it 'fails silently if PuSH hub forbids subscription' do
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 403)
|
||||
subject.call(account)
|
||||
end
|
||||
|
||||
it 'fails silently if PuSH hub is not found' do
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 404)
|
||||
subject.call(account)
|
||||
end
|
||||
|
||||
it 'fails loudly if there is a network error' do
|
||||
stub_request(:post, 'http://hub.example.com/').to_raise(HTTP::Error)
|
||||
expect { subject.call(account) }.to raise_error HTTP::Error
|
||||
end
|
||||
|
||||
it 'fails loudly if PuSH hub is unavailable' do
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 503)
|
||||
expect { subject.call(account) }.to raise_error Mastodon::UnexpectedResponseError
|
||||
end
|
||||
|
||||
it 'fails loudly if rate limited' do
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 429)
|
||||
expect { subject.call(account) }.to raise_error Mastodon::UnexpectedResponseError
|
||||
end
|
||||
end
|
|
@ -30,13 +30,6 @@ RSpec.describe UnblockService, type: :service do
|
|||
it 'destroys the blocking relation' do
|
||||
expect(sender.blocking?(bob)).to be false
|
||||
end
|
||||
|
||||
it 'sends an unblock salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:unblock])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'remote ActivityPub' do
|
||||
|
|
|
@ -30,13 +30,6 @@ RSpec.describe UnfollowService, type: :service do
|
|||
it 'destroys the following relation' do
|
||||
expect(sender.following?(bob)).to be false
|
||||
end
|
||||
|
||||
it 'sends an unfollow salmon slap' do
|
||||
expect(a_request(:post, "http://salmon.example.com/").with { |req|
|
||||
xml = OStatus2::Salmon.new.unpack(req.body)
|
||||
xml.match(OStatus::TagManager::VERBS[:unfollow])
|
||||
}).to have_been_made.once
|
||||
end
|
||||
end
|
||||
|
||||
describe 'remote ActivityPub' do
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UnsubscribeService, type: :service do
|
||||
let(:account) { Fabricate(:account, username: 'bob', domain: 'example.com', hub_url: 'http://hub.example.com') }
|
||||
subject { UnsubscribeService.new }
|
||||
|
||||
it 'removes the secret and resets expiration on account' do
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 204)
|
||||
subject.call(account)
|
||||
account.reload
|
||||
|
||||
expect(account.secret).to be_blank
|
||||
expect(account.subscription_expires_at).to be_blank
|
||||
end
|
||||
|
||||
it 'logs error on subscription failure' do
|
||||
logger = stub_logger
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 404)
|
||||
subject.call(account)
|
||||
|
||||
expect(logger).to have_received(:debug).with(/unsubscribe for bob@example.com failed/)
|
||||
end
|
||||
|
||||
it 'logs error on connection failure' do
|
||||
logger = stub_logger
|
||||
stub_request(:post, 'http://hub.example.com/').to_raise(HTTP::Error)
|
||||
subject.call(account)
|
||||
|
||||
expect(logger).to have_received(:debug).with(/unsubscribe for bob@example.com failed/)
|
||||
end
|
||||
|
||||
def stub_logger
|
||||
double(debug: nil).tap do |logger|
|
||||
allow(Rails).to receive(:logger).and_return(logger)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,84 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UpdateRemoteProfileService, type: :service do
|
||||
let(:xml) { File.read(Rails.root.join('spec', 'fixtures', 'push', 'feed.atom')) }
|
||||
|
||||
subject { UpdateRemoteProfileService.new }
|
||||
|
||||
before do
|
||||
stub_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png').to_return(request_fixture('avatar.txt'))
|
||||
end
|
||||
|
||||
context 'with updated details' do
|
||||
let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com') }
|
||||
|
||||
before do
|
||||
subject.call(xml, remote_account)
|
||||
end
|
||||
|
||||
it 'downloads new avatar' do
|
||||
expect(a_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png')).to have_been_made
|
||||
end
|
||||
|
||||
it 'sets the avatar remote url' do
|
||||
expect(remote_account.reload.avatar_remote_url).to eq 'https://quitter.no/avatar/7477-300-20160211190340.png'
|
||||
end
|
||||
|
||||
it 'sets display name' do
|
||||
expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
|
||||
end
|
||||
|
||||
it 'sets note' do
|
||||
expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with unchanged details' do
|
||||
let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com', display_name: 'DIGITAL CAT', note: 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes', avatar_remote_url: 'https://quitter.no/avatar/7477-300-20160211190340.png') }
|
||||
|
||||
before do
|
||||
subject.call(xml, remote_account)
|
||||
end
|
||||
|
||||
it 'does not re-download avatar' do
|
||||
expect(a_request(:get, 'https://quitter.no/avatar/7477-300-20160211190340.png')).to have_been_made.once
|
||||
end
|
||||
|
||||
it 'sets the avatar remote url' do
|
||||
expect(remote_account.reload.avatar_remote_url).to eq 'https://quitter.no/avatar/7477-300-20160211190340.png'
|
||||
end
|
||||
|
||||
it 'sets display name' do
|
||||
expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
|
||||
end
|
||||
|
||||
it 'sets note' do
|
||||
expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with updated details from a domain set to reject media' do
|
||||
let(:remote_account) { Fabricate(:account, username: 'bob', domain: 'example.com') }
|
||||
let!(:domain_block) { Fabricate(:domain_block, domain: 'example.com', reject_media: true) }
|
||||
|
||||
before do
|
||||
subject.call(xml, remote_account)
|
||||
end
|
||||
|
||||
it 'does not the avatar remote url' do
|
||||
expect(remote_account.reload.avatar_remote_url).to be_nil
|
||||
end
|
||||
|
||||
it 'sets display name' do
|
||||
expect(remote_account.reload.display_name).to eq 'DIGITAL CAT'
|
||||
end
|
||||
|
||||
it 'sets note' do
|
||||
expect(remote_account.reload.note).to eq 'Software engineer, free time musician and DIGITAL SPORTS enthusiast. Likes cats. Warning: May contain memes'
|
||||
end
|
||||
|
||||
it 'does not set store the avatar' do
|
||||
expect(remote_account.reload.avatar_file_name).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,59 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe AfterRemoteFollowRequestWorker do
|
||||
subject { described_class.new }
|
||||
let(:follow_request) { Fabricate(:follow_request) }
|
||||
describe 'perform' do
|
||||
context 'when the follow_request does not exist' do
|
||||
it 'catches a raise and returns true' do
|
||||
allow(FollowService).to receive(:new)
|
||||
result = subject.perform('aaa')
|
||||
|
||||
expect(result).to eq(true)
|
||||
expect(FollowService).not_to have_received(:new)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account cannot be updated' do
|
||||
it 'returns nil and does not call service when account is nil' do
|
||||
allow(FollowService).to receive(:new)
|
||||
service = double(call: nil)
|
||||
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
|
||||
|
||||
result = subject.perform(follow_request.id)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(FollowService).not_to have_received(:new)
|
||||
end
|
||||
|
||||
it 'returns nil and does not call service when account is locked' do
|
||||
allow(FollowService).to receive(:new)
|
||||
service = double(call: double(locked?: true))
|
||||
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
|
||||
|
||||
result = subject.perform(follow_request.id)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(FollowService).not_to have_received(:new)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is updated' do
|
||||
it 'calls the follow service and destroys the follow' do
|
||||
follow_service = double(call: nil)
|
||||
allow(FollowService).to receive(:new).and_return(follow_service)
|
||||
account = Fabricate(:account, locked: false)
|
||||
service = double(call: account)
|
||||
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
|
||||
|
||||
result = subject.perform(follow_request.id)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(follow_service).to have_received(:call).with(follow_request.account, account.acct)
|
||||
expect { follow_request.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,59 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe AfterRemoteFollowWorker do
|
||||
subject { described_class.new }
|
||||
let(:follow) { Fabricate(:follow) }
|
||||
describe 'perform' do
|
||||
context 'when the follow does not exist' do
|
||||
it 'catches a raise and returns true' do
|
||||
allow(FollowService).to receive(:new)
|
||||
result = subject.perform('aaa')
|
||||
|
||||
expect(result).to eq(true)
|
||||
expect(FollowService).not_to have_received(:new)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account cannot be updated' do
|
||||
it 'returns nil and does not call service when account is nil' do
|
||||
allow(FollowService).to receive(:new)
|
||||
service = double(call: nil)
|
||||
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
|
||||
|
||||
result = subject.perform(follow.id)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(FollowService).not_to have_received(:new)
|
||||
end
|
||||
|
||||
it 'returns nil and does not call service when account is not locked' do
|
||||
allow(FollowService).to receive(:new)
|
||||
service = double(call: double(locked?: false))
|
||||
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
|
||||
|
||||
result = subject.perform(follow.id)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(FollowService).not_to have_received(:new)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the account is updated' do
|
||||
it 'calls the follow service and destroys the follow' do
|
||||
follow_service = double(call: nil)
|
||||
allow(FollowService).to receive(:new).and_return(follow_service)
|
||||
account = Fabricate(:account, locked: true)
|
||||
service = double(call: account)
|
||||
allow(FetchRemoteAccountService).to receive(:new).and_return(service)
|
||||
|
||||
result = subject.perform(follow.id)
|
||||
|
||||
expect(result).to be_nil
|
||||
expect(follow_service).to have_received(:call).with(follow.account, account.acct)
|
||||
expect { follow.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,88 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Pubsubhubbub::ConfirmationWorker do
|
||||
include RoutingHelper
|
||||
|
||||
subject { described_class.new }
|
||||
|
||||
let!(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let!(:subscription) { Fabricate(:subscription, account: alice, callback_url: 'http://example.com/api', confirmed: false, expires_at: 3.days.from_now, secret: nil) }
|
||||
|
||||
describe 'perform' do
|
||||
describe 'with subscribe mode' do
|
||||
it 'confirms and updates subscription when challenge matches' do
|
||||
stub_random_value
|
||||
stub_request(:get, url_for_mode('subscribe'))
|
||||
.with(headers: http_headers)
|
||||
.to_return(status: 200, body: challenge_value, headers: {})
|
||||
|
||||
seconds = 10.days.seconds.to_i
|
||||
subject.perform(subscription.id, 'subscribe', 'asdf', seconds)
|
||||
|
||||
subscription.reload
|
||||
expect(subscription.secret).to eq 'asdf'
|
||||
expect(subscription.confirmed).to eq true
|
||||
expect(subscription.expires_at).to be_within(5).of(10.days.from_now)
|
||||
end
|
||||
|
||||
it 'does not update subscription when challenge does not match' do
|
||||
stub_random_value
|
||||
stub_request(:get, url_for_mode('subscribe'))
|
||||
.with(headers: http_headers)
|
||||
.to_return(status: 200, body: 'wrong value', headers: {})
|
||||
|
||||
seconds = 10.days.seconds.to_i
|
||||
subject.perform(subscription.id, 'subscribe', 'asdf', seconds)
|
||||
|
||||
subscription.reload
|
||||
expect(subscription.secret).to be_blank
|
||||
expect(subscription.confirmed).to eq false
|
||||
expect(subscription.expires_at).to be_within(5).of(3.days.from_now)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with unsubscribe mode' do
|
||||
it 'confirms and destroys subscription when challenge matches' do
|
||||
stub_random_value
|
||||
stub_request(:get, url_for_mode('unsubscribe'))
|
||||
.with(headers: http_headers)
|
||||
.to_return(status: 200, body: challenge_value, headers: {})
|
||||
|
||||
seconds = 10.days.seconds.to_i
|
||||
subject.perform(subscription.id, 'unsubscribe', 'asdf', seconds)
|
||||
|
||||
expect { subscription.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'does not destroy subscription when challenge does not match' do
|
||||
stub_random_value
|
||||
stub_request(:get, url_for_mode('unsubscribe'))
|
||||
.with(headers: http_headers)
|
||||
.to_return(status: 200, body: 'wrong value', headers: {})
|
||||
|
||||
seconds = 10.days.seconds.to_i
|
||||
subject.perform(subscription.id, 'unsubscribe', 'asdf', seconds)
|
||||
|
||||
expect { subscription.reload }.not_to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def url_for_mode(mode)
|
||||
"http://example.com/api?hub.challenge=#{challenge_value}&hub.lease_seconds=863999&hub.mode=#{mode}&hub.topic=https://#{Rails.configuration.x.local_domain}/users/alice.atom"
|
||||
end
|
||||
|
||||
def stub_random_value
|
||||
allow(SecureRandom).to receive(:hex).and_return(challenge_value)
|
||||
end
|
||||
|
||||
def challenge_value
|
||||
'1a2s3d4f'
|
||||
end
|
||||
|
||||
def http_headers
|
||||
{ 'Connection' => 'close', 'Host' => 'example.com' }
|
||||
end
|
||||
end
|
|
@ -1,68 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
describe Pubsubhubbub::DeliveryWorker do
|
||||
include RoutingHelper
|
||||
subject { described_class.new }
|
||||
|
||||
let(:payload) { 'test' }
|
||||
|
||||
describe 'perform' do
|
||||
it 'raises when subscription does not exist' do
|
||||
expect { subject.perform 123, payload }.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
it 'does not attempt to deliver when domain blocked' do
|
||||
_domain_block = Fabricate(:domain_block, domain: 'example.com', severity: :suspend)
|
||||
subscription = Fabricate(:subscription, callback_url: 'https://example.com/api', last_successful_delivery_at: 2.days.ago)
|
||||
|
||||
subject.perform(subscription.id, payload)
|
||||
|
||||
expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(2.days.ago)
|
||||
end
|
||||
|
||||
it 'raises when request fails' do
|
||||
subscription = Fabricate(:subscription)
|
||||
|
||||
stub_request_to_respond_with(subscription, 500)
|
||||
expect { subject.perform(subscription.id, payload) }.to raise_error Mastodon::UnexpectedResponseError
|
||||
end
|
||||
|
||||
it 'updates subscriptions when delivery succeeds' do
|
||||
subscription = Fabricate(:subscription)
|
||||
|
||||
stub_request_to_respond_with(subscription, 200)
|
||||
subject.perform(subscription.id, payload)
|
||||
|
||||
expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(Time.now.utc)
|
||||
end
|
||||
|
||||
it 'updates subscription without a secret when delivery succeeds' do
|
||||
subscription = Fabricate(:subscription, secret: nil)
|
||||
|
||||
stub_request_to_respond_with(subscription, 200)
|
||||
subject.perform(subscription.id, payload)
|
||||
|
||||
expect(subscription.reload.last_successful_delivery_at).to be_within(2).of(Time.now.utc)
|
||||
end
|
||||
|
||||
def stub_request_to_respond_with(subscription, code)
|
||||
stub_request(:post, 'http://example.com/callback')
|
||||
.with(body: payload, headers: expected_headers(subscription))
|
||||
.to_return(status: code, body: '', headers: {})
|
||||
end
|
||||
|
||||
def expected_headers(subscription)
|
||||
{
|
||||
'Connection' => 'close',
|
||||
'Content-Type' => 'application/atom+xml',
|
||||
'Host' => 'example.com',
|
||||
'Link' => "<https://#{Rails.configuration.x.local_domain}/api/push>; rel=\"hub\", <https://#{Rails.configuration.x.local_domain}/users/#{subscription.account.username}.atom>; rel=\"self\"",
|
||||
}.tap do |basic|
|
||||
known_digest = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), subscription.secret.to_s, payload)
|
||||
basic.merge('X-Hub-Signature' => "sha1=#{known_digest}") if subscription.secret?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,46 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe Pubsubhubbub::DistributionWorker do
|
||||
subject { Pubsubhubbub::DistributionWorker.new }
|
||||
|
||||
let!(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let!(:bob) { Fabricate(:account, username: 'bob', domain: 'example2.com') }
|
||||
let!(:anonymous_subscription) { Fabricate(:subscription, account: alice, callback_url: 'http://example1.com', confirmed: true, lease_seconds: 3600) }
|
||||
let!(:subscription_with_follower) { Fabricate(:subscription, account: alice, callback_url: 'http://example2.com', confirmed: true, lease_seconds: 3600) }
|
||||
|
||||
before do
|
||||
bob.follow!(alice)
|
||||
end
|
||||
|
||||
describe 'with public status' do
|
||||
let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :public) }
|
||||
|
||||
it 'delivers payload to all subscriptions' do
|
||||
allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
|
||||
subject.perform(status.stream_entry.id)
|
||||
expect(Pubsubhubbub::DeliveryWorker).to have_received(:push_bulk).with([anonymous_subscription.id, subscription_with_follower.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when OStatus privacy is not used' do
|
||||
describe 'with private status' do
|
||||
let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :private) }
|
||||
|
||||
it 'does not deliver anything' do
|
||||
allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
|
||||
subject.perform(status.stream_entry.id)
|
||||
expect(Pubsubhubbub::DeliveryWorker).to_not have_received(:push_bulk)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with direct status' do
|
||||
let(:status) { Fabricate(:status, account: alice, text: 'Hello', visibility: :direct) }
|
||||
|
||||
it 'does not deliver payload' do
|
||||
allow(Pubsubhubbub::DeliveryWorker).to receive(:push_bulk)
|
||||
subject.perform(status.stream_entry.id)
|
||||
expect(Pubsubhubbub::DeliveryWorker).to_not have_received(:push_bulk)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,19 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe Scheduler::SubscriptionsScheduler do
|
||||
subject { Scheduler::SubscriptionsScheduler.new }
|
||||
|
||||
let!(:expiring_account1) { Fabricate(:account, subscription_expires_at: 20.minutes.from_now, domain: 'example.com', followers_count: 1, hub_url: 'http://hub.example.com') }
|
||||
let!(:expiring_account2) { Fabricate(:account, subscription_expires_at: 4.hours.from_now, domain: 'example.org', followers_count: 1, hub_url: 'http://hub.example.org') }
|
||||
|
||||
before do
|
||||
stub_request(:post, 'http://hub.example.com/').to_return(status: 202)
|
||||
stub_request(:post, 'http://hub.example.org/').to_return(status: 202)
|
||||
end
|
||||
|
||||
it 're-subscribes for all expiring accounts' do
|
||||
subject.perform
|
||||
expect(a_request(:post, 'http://hub.example.com/')).to have_been_made.once
|
||||
expect(a_request(:post, 'http://hub.example.org/')).to have_been_made.once
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue