Merge upstream changes from v4.0.15 (#1344)
This includes the security content of Mastodon 4.0.15/4.2.7. https://github.com/mastodon/mastodon/releases/tag/v4.2.7 --------- Co-authored-by: Claire <claire.github-309c@sitedethib.com> Co-authored-by: Matt Jankowski <matt@jankowski.online>
This commit is contained in:
parent
3c9599f19a
commit
ba20b7d86a
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -8,6 +8,16 @@ All notable changes to this project will be documented in this file.
|
||||||
**The 4.0.x branch has reached its end of life and will not receive any further update.**
|
**The 4.0.x branch has reached its end of life and will not receive any further update.**
|
||||||
This means that no security fix will be made available for this branch after this date, and you will need to update to a more recent version (such as the 4.2.x branch) to receive security fixes.
|
This means that no security fix will be made available for this branch after this date, and you will need to update to a more recent version (such as the 4.2.x branch) to receive security fixes.
|
||||||
|
|
||||||
|
## [4.0.15] - 2024-02-16
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix OmniAuth tests and edge cases in error handling ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29201), [ClearlyClaire](https://github.com/mastodon/mastodon/pull/29207))
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Fix insufficient checking of remote posts ([GHSA-jhrq-qvrm-qr36](https://github.com/mastodon/mastodon/security/advisories/GHSA-jhrq-qvrm-qr36))
|
||||||
|
|
||||||
## [4.0.14] - 2024-02-14
|
## [4.0.14] - 2024-02-14
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
|
@ -24,6 +24,9 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||||
session["devise.#{provider}_data"] = request.env['omniauth.auth']
|
session["devise.#{provider}_data"] = request.env['omniauth.auth']
|
||||||
redirect_to new_user_registration_url
|
redirect_to new_user_registration_url
|
||||||
end
|
end
|
||||||
|
rescue ActiveRecord::RecordInvalid
|
||||||
|
flash[:alert] = I18n.t('devise.failure.omniauth_user_creation_failure') if is_navigational_format?
|
||||||
|
redirect_to new_user_session_url
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,19 @@ module JsonLdHelper
|
||||||
build_request(uri, on_behalf_of).perform do |response|
|
build_request(uri, on_behalf_of).perform do |response|
|
||||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error
|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || !raise_on_temporary_error
|
||||||
|
|
||||||
body_to_json(response.body_with_limit) if response.code == 200
|
body_to_json(response.body_with_limit) if response.code == 200 && valid_activitypub_content_type?(response)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_activitypub_content_type?(response)
|
||||||
|
return true if response.mime_type == 'application/activity+json'
|
||||||
|
|
||||||
|
# When the mime type is `application/ld+json`, we need to check the profile,
|
||||||
|
# but `http.rb` does not parse it for us.
|
||||||
|
return false unless response.mime_type == 'application/ld+json'
|
||||||
|
|
||||||
|
response.headers[HTTP::Headers::CONTENT_TYPE]&.split(';')&.map(&:strip)&.any? do |str|
|
||||||
|
str.start_with?('profile="') && str[9...-1].split.include?('https://www.w3.org/ns/activitystreams')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ class FetchResourceService < BaseService
|
||||||
@response_code = response.code
|
@response_code = response.code
|
||||||
return nil if response.code != 200
|
return nil if response.code != 200
|
||||||
|
|
||||||
if ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
|
if valid_activitypub_content_type?(response)
|
||||||
body = response.body_with_limit
|
body = response.body_with_limit
|
||||||
json = body_to_json(body)
|
json = body_to_json(body)
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ en:
|
||||||
last_attempt: You have one more attempt before your account is locked.
|
last_attempt: You have one more attempt before your account is locked.
|
||||||
locked: Your account is locked.
|
locked: Your account is locked.
|
||||||
not_found_in_database: Invalid %{authentication_keys} or password.
|
not_found_in_database: Invalid %{authentication_keys} or password.
|
||||||
|
omniauth_user_creation_failure: Error creating an account for this identity.
|
||||||
pending: Your account is still under review.
|
pending: Your account is still under review.
|
||||||
timeout: Your session expired. Please sign in again to continue.
|
timeout: Your session expired. Please sign in again to continue.
|
||||||
unauthenticated: You need to sign in or sign up before continuing.
|
unauthenticated: You need to sign in or sign up before continuing.
|
||||||
|
|
|
@ -56,7 +56,7 @@ services:
|
||||||
|
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
image: ghcr.io/mastodon/mastodon:v4.0.14
|
image: ghcr.io/mastodon/mastodon:v4.0.15
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
|
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
|
||||||
|
@ -77,7 +77,7 @@ services:
|
||||||
|
|
||||||
streaming:
|
streaming:
|
||||||
build: .
|
build: .
|
||||||
image: ghcr.io/mastodon/mastodon:v4.0.14
|
image: ghcr.io/mastodon/mastodon:v4.0.15
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: node ./streaming
|
command: node ./streaming
|
||||||
|
@ -95,7 +95,7 @@ services:
|
||||||
|
|
||||||
sidekiq:
|
sidekiq:
|
||||||
build: .
|
build: .
|
||||||
image: ghcr.io/mastodon/mastodon:v4.0.14
|
image: ghcr.io/mastodon/mastodon:v4.0.15
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bundle exec sidekiq
|
command: bundle exec sidekiq
|
||||||
|
|
|
@ -13,7 +13,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def patch
|
def patch
|
||||||
14
|
15
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags
|
def flags
|
||||||
|
|
|
@ -56,15 +56,15 @@ describe JsonLdHelper do
|
||||||
describe '#fetch_resource' do
|
describe '#fetch_resource' do
|
||||||
context 'when the second argument is false' do
|
context 'when the second argument is false' do
|
||||||
it 'returns resource even if the retrieved ID and the given URI does not match' do
|
it 'returns resource even if the retrieved ID and the given URI does not match' do
|
||||||
stub_request(:get, 'https://bob.test/').to_return body: '{"id": "https://alice.test/"}'
|
stub_request(:get, 'https://bob.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://alice.test/').to_return body: '{"id": "https://alice.test/"}'
|
stub_request(:get, 'https://alice.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
|
||||||
|
|
||||||
expect(fetch_resource('https://bob.test/', false)).to eq({ 'id' => 'https://alice.test/' })
|
expect(fetch_resource('https://bob.test/', false)).to eq({ 'id' => 'https://alice.test/' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns nil if the object identified by the given URI and the object identified by the retrieved ID does not match' do
|
it 'returns nil if the object identified by the given URI and the object identified by the retrieved ID does not match' do
|
||||||
stub_request(:get, 'https://mallory.test/').to_return body: '{"id": "https://marvin.test/"}'
|
stub_request(:get, 'https://mallory.test/').to_return(body: '{"id": "https://marvin.test/"}', headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://marvin.test/').to_return body: '{"id": "https://alice.test/"}'
|
stub_request(:get, 'https://marvin.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
|
||||||
|
|
||||||
expect(fetch_resource('https://mallory.test/', false)).to eq nil
|
expect(fetch_resource('https://mallory.test/', false)).to eq nil
|
||||||
end
|
end
|
||||||
|
@ -72,7 +72,7 @@ describe JsonLdHelper do
|
||||||
|
|
||||||
context 'when the second argument is true' do
|
context 'when the second argument is true' do
|
||||||
it 'returns nil if the retrieved ID and the given URI does not match' do
|
it 'returns nil if the retrieved ID and the given URI does not match' do
|
||||||
stub_request(:get, 'https://mallory.test/').to_return body: '{"id": "https://alice.test/"}'
|
stub_request(:get, 'https://mallory.test/').to_return(body: '{"id": "https://alice.test/"}', headers: { 'Content-Type': 'application/activity+json' })
|
||||||
expect(fetch_resource('https://mallory.test/', true)).to eq nil
|
expect(fetch_resource('https://mallory.test/', true)).to eq nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -80,12 +80,12 @@ describe JsonLdHelper do
|
||||||
|
|
||||||
describe '#fetch_resource_without_id_validation' do
|
describe '#fetch_resource_without_id_validation' do
|
||||||
it 'returns nil if the status code is not 200' do
|
it 'returns nil if the status code is not 200' do
|
||||||
stub_request(:get, 'https://host.test/').to_return status: 400, body: '{}'
|
stub_request(:get, 'https://host.test/').to_return(status: 400, body: '{}', headers: { 'Content-Type': 'application/activity+json' })
|
||||||
expect(fetch_resource_without_id_validation('https://host.test/')).to eq nil
|
expect(fetch_resource_without_id_validation('https://host.test/')).to eq nil
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns hash' do
|
it 'returns hash' do
|
||||||
stub_request(:get, 'https://host.test/').to_return status: 200, body: '{}'
|
stub_request(:get, 'https://host.test/').to_return(status: 200, body: '{}', headers: { 'Content-Type': 'application/activity+json' })
|
||||||
expect(fetch_resource_without_id_validation('https://host.test/')).to eq({})
|
expect(fetch_resource_without_id_validation('https://host.test/')).to eq({})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,7 +33,7 @@ RSpec.describe ActivityPub::Activity::Announce do
|
||||||
context 'when sender is followed by a local account' do
|
context 'when sender is followed by a local account' do
|
||||||
before do
|
before do
|
||||||
Fabricate(:account).follow!(sender)
|
Fabricate(:account).follow!(sender)
|
||||||
stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json))
|
stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
subject.perform
|
subject.perform
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ RSpec.describe ActivityPub::Activity::Announce do
|
||||||
subject { described_class.new(json, sender, relayed_through_actor: relay_account) }
|
subject { described_class.new(json, sender, relayed_through_actor: relay_account) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json))
|
stub_request(:get, 'https://example.com/actor/hello-world').to_return(body: Oj.dump(unknown_object_json), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'and the relay is enabled' do
|
context 'and the relay is enabled' do
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'OmniAuth callbacks' do
|
||||||
|
shared_examples 'omniauth provider callbacks' do |provider|
|
||||||
|
subject { post send :"user_#{provider}_omniauth_callback_path" }
|
||||||
|
|
||||||
|
context 'with full information in response' do
|
||||||
|
before do
|
||||||
|
mock_omniauth(provider, {
|
||||||
|
provider: provider.to_s,
|
||||||
|
uid: '123',
|
||||||
|
info: {
|
||||||
|
verified: 'true',
|
||||||
|
email: 'user@host.example',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without a matching user' do
|
||||||
|
it 'creates a user and an identity and redirects to root path' do
|
||||||
|
expect { subject }
|
||||||
|
.to change(User, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(Identity, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(LoginActivity, :count)
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(User.last.email).to eq('user@host.example')
|
||||||
|
expect(Identity.find_by(user: User.last).uid).to eq('123')
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a matching user and no matching identity' do
|
||||||
|
before do
|
||||||
|
Fabricate(:user, email: 'user@host.example')
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH is set to true' do
|
||||||
|
around do |example|
|
||||||
|
ClimateControl.modify ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH: 'true' do
|
||||||
|
example.run
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'matches the existing user, creates an identity, and redirects to root path' do
|
||||||
|
expect { subject }
|
||||||
|
.to not_change(User, :count)
|
||||||
|
.and change(Identity, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(LoginActivity, :count)
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(Identity.find_by(user: User.last).uid).to eq('123')
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ALLOW_UNSAFE_AUTH_PROVIDER_REATTACH is not set to true' do
|
||||||
|
it 'does not match the existing user or create an identity, and redirects to login page' do
|
||||||
|
expect { subject }
|
||||||
|
.to not_change(User, :count)
|
||||||
|
.and not_change(Identity, :count)
|
||||||
|
.and not_change(LoginActivity, :count)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(new_user_session_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a matching user and a matching identity' do
|
||||||
|
before do
|
||||||
|
user = Fabricate(:user, email: 'user@host.example')
|
||||||
|
Fabricate(:identity, user: user, uid: '123', provider: provider)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'matches the existing records and redirects to root path' do
|
||||||
|
expect { subject }
|
||||||
|
.to not_change(User, :count)
|
||||||
|
.and not_change(Identity, :count)
|
||||||
|
.and change(LoginActivity, :count)
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a response missing email address' do
|
||||||
|
before do
|
||||||
|
mock_omniauth(provider, {
|
||||||
|
provider: provider.to_s,
|
||||||
|
uid: '123',
|
||||||
|
info: {
|
||||||
|
verified: 'true',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to the auth setup page' do
|
||||||
|
expect { subject }
|
||||||
|
.to change(User, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(Identity, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(LoginActivity, :count)
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(auth_setup_path(missing_email: '1'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a user cannot be built' do
|
||||||
|
before do
|
||||||
|
allow(User).to receive(:find_for_omniauth).and_return(User.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to the new user signup page' do
|
||||||
|
expect { subject }
|
||||||
|
.to not_change(User, :count)
|
||||||
|
.and not_change(Identity, :count)
|
||||||
|
.and not_change(LoginActivity, :count)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(new_user_registration_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#openid_connect', if: ENV['OIDC_ENABLED'] == 'true' && ENV['OIDC_SCOPE'].present? do
|
||||||
|
include_examples 'omniauth provider callbacks', :openid_connect
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#cas', if: ENV['CAS_ENABLED'] == 'true' do
|
||||||
|
include_examples 'omniauth provider callbacks', :cas
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#saml', if: ENV['SAML_ENABLED'] == 'true' do
|
||||||
|
include_examples 'omniauth provider callbacks', :saml
|
||||||
|
end
|
||||||
|
end
|
|
@ -60,10 +60,10 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
||||||
|
|
||||||
shared_examples 'sets pinned posts' do
|
shared_examples 'sets pinned posts' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/account/pinned/1').to_return(status: 200, body: Oj.dump(status_json_1))
|
stub_request(:get, 'https://example.com/account/pinned/1').to_return(status: 200, body: Oj.dump(status_json_1), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/account/pinned/2').to_return(status: 200, body: Oj.dump(status_json_2))
|
stub_request(:get, 'https://example.com/account/pinned/2').to_return(status: 200, body: Oj.dump(status_json_2), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/account/pinned/3').to_return(status: 404)
|
stub_request(:get, 'https://example.com/account/pinned/3').to_return(status: 404)
|
||||||
stub_request(:get, 'https://example.com/account/pinned/4').to_return(status: 200, body: Oj.dump(status_json_4))
|
stub_request(:get, 'https://example.com/account/pinned/4').to_return(status: 200, body: Oj.dump(status_json_4), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
|
|
||||||
subject.call(actor, note: true, hashtag: false)
|
subject.call(actor, note: true, hashtag: false)
|
||||||
end
|
end
|
||||||
|
@ -76,7 +76,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
||||||
describe '#call' do
|
describe '#call' do
|
||||||
context 'when the endpoint is a Collection' do
|
context 'when the endpoint is a Collection' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'sets pinned posts'
|
it_behaves_like 'sets pinned posts'
|
||||||
|
@ -93,7 +93,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'sets pinned posts'
|
it_behaves_like 'sets pinned posts'
|
||||||
|
@ -114,7 +114,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'sets pinned posts'
|
it_behaves_like 'sets pinned posts'
|
||||||
|
|
|
@ -36,7 +36,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
|
||||||
describe '#call' do
|
describe '#call' do
|
||||||
context 'when the endpoint is a Collection' do
|
context 'when the endpoint is a Collection' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'sets featured tags'
|
it_behaves_like 'sets featured tags'
|
||||||
|
@ -44,7 +44,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
|
||||||
|
|
||||||
context 'when the account already has featured tags' do
|
context 'when the account already has featured tags' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
|
|
||||||
actor.featured_tags.create!(name: 'FoO')
|
actor.featured_tags.create!(name: 'FoO')
|
||||||
actor.featured_tags.create!(name: 'baz')
|
actor.featured_tags.create!(name: 'baz')
|
||||||
|
@ -65,7 +65,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'sets featured tags'
|
it_behaves_like 'sets featured tags'
|
||||||
|
@ -86,7 +86,7 @@ RSpec.describe ActivityPub::FetchFeaturedTagsCollectionService, type: :service d
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'sets featured tags'
|
it_behaves_like 'sets featured tags'
|
||||||
|
|
|
@ -42,7 +42,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
|
||||||
before do
|
before do
|
||||||
actor[:inbox] = nil
|
actor[:inbox] = nil
|
||||||
|
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
|
||||||
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
|
||||||
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
@ -123,7 +123,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
|
||||||
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
|
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ RSpec.describe ActivityPub::FetchRemoteAccountService, type: :service do
|
||||||
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
|
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,7 +42,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
|
||||||
before do
|
before do
|
||||||
actor[:inbox] = nil
|
actor[:inbox] = nil
|
||||||
|
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
|
||||||
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
|
||||||
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/alice' }] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
@ -123,7 +123,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
|
||||||
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
|
let!(:webfinger) { { subject: 'acct:alice@example.com', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ RSpec.describe ActivityPub::FetchRemoteActorService, type: :service do
|
||||||
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
|
let!(:webfinger) { { subject: 'acct:alice@iscool.af', links: [{ rel: 'self', href: 'https://example.com/bob' }] } }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://iscool.af/.well-known/webfinger?resource=acct:alice@iscool.af').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,7 +38,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor))
|
stub_request(:get, 'https://example.com/alice').to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
stub_request(:get, 'https://example.com/.well-known/webfinger?resource=acct:alice@example.com').to_return(body: Oj.dump(webfinger), headers: { 'Content-Type': 'application/jrd+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
|
||||||
|
|
||||||
context 'when the key is a sub-object from the actor' do
|
context 'when the key is a sub-object from the actor' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, public_key_id).to_return(body: Oj.dump(actor))
|
stub_request(:get, public_key_id).to_return(body: Oj.dump(actor), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns the expected account' do
|
it 'returns the expected account' do
|
||||||
|
@ -59,7 +59,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
|
||||||
let(:public_key_id) { 'https://example.com/alice-public-key.json' }
|
let(:public_key_id) { 'https://example.com/alice-public-key.json' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })))
|
stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns the expected account' do
|
it 'returns the expected account' do
|
||||||
|
@ -72,7 +72,7 @@ RSpec.describe ActivityPub::FetchRemoteKeyService, type: :service do
|
||||||
let(:actor_public_key) { 'https://example.com/alice-public-key.json' }
|
let(:actor_public_key) { 'https://example.com/alice-public-key.json' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })))
|
stub_request(:get, public_key_id).to_return(body: Oj.dump(key_json.merge({ '@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'] })), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns the nil' do
|
it 'returns the nil' do
|
||||||
|
|
|
@ -41,7 +41,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
|
||||||
|
|
||||||
context 'when passing the URL to the collection' do
|
context 'when passing the URL to the collection' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'spawns workers for up to 5 replies on the same server' do
|
it 'spawns workers for up to 5 replies on the same server' do
|
||||||
|
@ -70,7 +70,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
|
||||||
|
|
||||||
context 'when passing the URL to the collection' do
|
context 'when passing the URL to the collection' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'spawns workers for up to 5 replies on the same server' do
|
it 'spawns workers for up to 5 replies on the same server' do
|
||||||
|
@ -103,7 +103,7 @@ RSpec.describe ActivityPub::FetchRepliesService, type: :service do
|
||||||
|
|
||||||
context 'when passing the URL to the collection' do
|
context 'when passing the URL to the collection' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'spawns workers for up to 5 replies on the same server' do
|
it 'spawns workers for up to 5 replies on the same server' do
|
||||||
|
|
|
@ -58,7 +58,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
|
||||||
describe '#call' do
|
describe '#call' do
|
||||||
context 'when the endpoint is a Collection of actor URIs' do
|
context 'when the endpoint is a Collection of actor URIs' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'synchronizes followers'
|
it_behaves_like 'synchronizes followers'
|
||||||
|
@ -75,7 +75,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'synchronizes followers'
|
it_behaves_like 'synchronizes followers'
|
||||||
|
@ -96,7 +96,7 @@ RSpec.describe ActivityPub::SynchronizeFollowersService, type: :service do
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload))
|
stub_request(:get, collection_uri).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'synchronizes followers'
|
it_behaves_like 'synchronizes followers'
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
OmniAuth.config.test_mode = true
|
||||||
|
|
||||||
|
def mock_omniauth(provider, data)
|
||||||
|
OmniAuth.config.mock_auth[provider] = OmniAuth::AuthHash.new(data)
|
||||||
|
end
|
|
@ -21,7 +21,7 @@ describe ActivityPub::FetchRepliesWorker do
|
||||||
|
|
||||||
describe 'perform' do
|
describe 'perform' do
|
||||||
it 'performs a request if the collection URI is from the same host' do
|
it 'performs a request if the collection URI is from the same host' do
|
||||||
stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json)
|
stub_request(:get, 'https://example.com/statuses_replies/1').to_return(status: 200, body: json, headers: { 'Content-Type': 'application/activity+json' })
|
||||||
subject.perform(status.id, 'https://example.com/statuses_replies/1')
|
subject.perform(status.id, 'https://example.com/statuses_replies/1')
|
||||||
expect(a_request(:get, 'https://example.com/statuses_replies/1')).to have_been_made.once
|
expect(a_request(:get, 'https://example.com/statuses_replies/1')).to have_been_made.once
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue