Skip to content

Commit

Permalink
Merge tag 'v4.2.7'
Browse files Browse the repository at this point in the history
  • Loading branch information
fono09 committed Feb 16, 2024
2 parents 25bf1bf + 0e4e98f commit e6a4927
Show file tree
Hide file tree
Showing 20 changed files with 111 additions and 71 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

All notable changes to this project will be documented in this file.

## [4.2.7] - 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))
- Fix new installs by upgrading to the latest release of the `nsa` gem, instead of a no longer existing commit ([mjankowski](https://github.com/mastodon/mastodon/pull/29065))

### Security

- Fix insufficient checking of remote posts ([GHSA-jhrq-qvrm-qr36](https://github.com/mastodon/mastodon/security/advisories/GHSA-jhrq-qvrm-qr36))

## [4.2.6] - 2024-02-14

### Security
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ gem 'kaminari', '~> 1.2'
gem 'link_header', '~> 0.0'
gem 'mime-types', '~> 3.5.0', require: 'mime/types/columnar'
gem 'nokogiri', '~> 1.15'
gem 'nsa', github: 'jhawthorn/nsa', ref: 'e020fcc3a54d993ab45b7194d89ab720296c111b'
gem 'nsa'
gem 'oj', '~> 3.14'
gem 'ox', '~> 2.14'
gem 'parslet'
Expand Down
20 changes: 7 additions & 13 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,6 @@ GIT
hkdf (~> 0.2)
jwt (~> 2.0)

GIT
remote: https://github.com/jhawthorn/nsa.git
revision: e020fcc3a54d993ab45b7194d89ab720296c111b
ref: e020fcc3a54d993ab45b7194d89ab720296c111b
specs:
nsa (0.2.8)
activesupport (>= 4.2, < 7.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (>= 3.5)
statsd-ruby (~> 1.4, >= 1.4.0)

GIT
remote: https://github.com/mastodon/rails-settings-cached.git
revision: 86328ef0bd04ce21cc0504ff5e334591e8c2ccab
Expand Down Expand Up @@ -483,6 +472,11 @@ GEM
nokogiri (1.16.2)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nsa (0.3.0)
activesupport (>= 4.2, < 7.2)
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (>= 3.5)
statsd-ruby (~> 1.4, >= 1.4.0)
oj (3.16.1)
omniauth (2.1.1)
hashie (>= 3.4.6)
Expand Down Expand Up @@ -520,7 +514,7 @@ GEM
parslet (2.0.0)
pastel (0.8.0)
tty-color (~> 0.5)
pg (1.5.4)
pg (1.5.5)
pghero (3.3.4)
activerecord (>= 6)
posix-spawn (0.3.15)
Expand Down Expand Up @@ -884,7 +878,7 @@ DEPENDENCIES
net-http (~> 0.3.2)
net-ldap (~> 0.18)
nokogiri (~> 1.15)
nsa!
nsa
oj (~> 3.14)
omniauth (~> 2.0)
omniauth-cas!
Expand Down
3 changes: 3 additions & 0 deletions app/controllers/auth/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ def self.provides_callback_for(provider)
session["devise.#{provider}_data"] = request.env['omniauth.auth']
redirect_to new_user_registration_url
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

Expand Down
14 changes: 13 additions & 1 deletion app/helpers/jsonld_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,19 @@ def fetch_resource_without_id_validation(uri, on_behalf_of = nil, raise_on_tempo
build_request(uri, on_behalf_of, options: request_options).perform do |response|
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

Expand Down
2 changes: 1 addition & 1 deletion app/services/fetch_resource_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def process_response(response, terminal = false)
@response_code = response.code
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
json = body_to_json(body)

Expand Down
1 change: 1 addition & 0 deletions config/locales/devise.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ en:
last_attempt: You have one more attempt before your account is locked.
locked: Your account is locked.
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.
timeout: Your session expired. Please login again to continue.
unauthenticated: You need to login or sign up before continuing.
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ services:

web: &web
build: .
image: ghcr.io/mastodon/mastodon:v4.2.6
image: ghcr.io/mastodon/mastodon:v4.2.7
restart: always
env_file: .env.production
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
Expand Down Expand Up @@ -151,7 +151,7 @@ services:

streaming:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.6
image: ghcr.io/mastodon/mastodon:v4.2.7
restart: always
env_file: .env.production
command: node ./streaming
Expand All @@ -174,7 +174,7 @@ services:

sidekiq:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.6
image: ghcr.io/mastodon/mastodon:v4.2.7
restart: always
env_file: .env.production
command: bundle exec sidekiq
Expand Down
2 changes: 1 addition & 1 deletion lib/mastodon/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def minor
end

def patch
6
7
end

def default_prerelease
Expand Down
14 changes: 7 additions & 7 deletions spec/helpers/jsonld_helper_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,36 +56,36 @@
describe '#fetch_resource' 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
stub_request(:get, 'https://bob.test/').to_return body: '{"id": "https://alice.test/"}'
stub_request(:get, 'https://alice.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/"}', headers: { 'Content-Type': 'application/activity+json' })

expect(fetch_resource('https://bob.test/', false)).to eq({ 'id' => 'https://alice.test/' })
end

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://marvin.test/').to_return body: '{"id": "https://alice.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/"}', headers: { 'Content-Type': 'application/activity+json' })

expect(fetch_resource('https://mallory.test/', false)).to be_nil
end
end

context 'when the second argument is true' 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 be_nil
end
end
end

describe '#fetch_resource_without_id_validation' 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 be_nil
end

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({})
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/lib/activitypub/activity/announce_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
context 'when sender is followed by a local account' do
before do
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
end

Expand Down Expand Up @@ -120,7 +120,7 @@
let(:object_json) { 'https://example.com/actor/hello-world' }

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

context 'when the relay is enabled' do
Expand Down
37 changes: 28 additions & 9 deletions spec/requests/omniauth_callbacks_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,35 @@
Fabricate(:user, email: 'user@host.example')
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)
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

expect(Identity.find_by(user: User.last).uid).to eq('123')
expect(response).to redirect_to(root_path)
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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@

shared_examples 'sets pinned posts' do
before do
stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known))
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined))
stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined), headers: { 'Content-Type': 'application/activity+json' })
stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404)
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })

subject.call(actor, note: true, hashtag: false)
end
Expand All @@ -82,7 +82,7 @@
describe '#call' do
context 'when the endpoint is a Collection' 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

it_behaves_like 'sets pinned posts'
Expand All @@ -99,7 +99,7 @@
end

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

it_behaves_like 'sets pinned posts'
Expand All @@ -108,7 +108,7 @@
let(:items) { 'https://example.com/account/pinned/unknown-reachable' }

before do
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
subject.call(actor, note: true, hashtag: false)
end

Expand All @@ -135,7 +135,7 @@
end

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

it_behaves_like 'sets pinned posts'
Expand All @@ -144,7 +144,7 @@
let(:items) { 'https://example.com/account/pinned/unknown-reachable' }

before do
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable))
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
subject.call(actor, note: true, hashtag: false)
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@
describe '#call' do
context 'when the endpoint is a Collection' 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

it_behaves_like 'sets featured tags'
end

context 'when the account already has featured tags' 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: 'baz')
Expand All @@ -67,7 +67,7 @@
end

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

it_behaves_like 'sets featured tags'
Expand All @@ -88,7 +88,7 @@
end

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

it_behaves_like 'sets featured tags'
Expand Down
Loading

0 comments on commit e6a4927

Please sign in to comment.