Skip to content

Commit

Permalink
Merge tag 'v4.2.10' into hometown-4.2-merge
Browse files Browse the repository at this point in the history
  • Loading branch information
dariusk committed Jul 4, 2024
2 parents e09be08 + a5b4a2b commit 441dca1
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 18 deletions.
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,37 @@

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

## [4.2.10] - 2024-07-04

### Security

- Fix incorrect permission checking on multiple API endpoints ([GHSA-58x8-3qxw-6hm7](https://github.com/mastodon/mastodon/security/advisories/GHSA-58x8-3qxw-6hm7))
- Fix incorrect authorship checking when processing some activities (CVE-2024-37903, [GHSA-xjvf-fm67-4qc3](https://github.com/mastodon/mastodon/security/advisories/GHSA-xjvf-fm67-4qc3))
- Fix ongoing streaming sessions not being invalidated when application tokens get revoked ([GHSA-vp5r-5pgw-jwqx](https://github.com/mastodon/mastodon/security/advisories/GHSA-vp5r-5pgw-jwqx))
- Update dependencies

### Added

- Add yarn version specification to avoid confusion with Yarn 3 and Yarn 4

### Changed

- Change preview cards generation to skip unusually long URLs ([oneiros](https://github.com/mastodon/mastodon/pull/30854))
- Change search modifiers to be case-insensitive ([Gargron](https://github.com/mastodon/mastodon/pull/30865))
- Change `STATSD_ADDR` handling to emit a warning rather than crashing if the address is unreachable ([timothyjrogers](https://github.com/mastodon/mastodon/pull/30691))
- Change PWA start URL from `/home` to `/` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/27377))

### Removed

- Removed dependency on `posix-spawn` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/18559))

### Fixed

- Fix scheduled statuses scheduled in less than 5 minutes being immediately published ([danielmbrasil](https://github.com/mastodon/mastodon/pull/30584))
- Fix encoding detection for link cards ([oneiros](https://github.com/mastodon/mastodon/pull/30780))
- Fix `/admin/accounts/:account_id/statuses/:id` for edited posts with media attachments ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30819))
- Fix duplicate `@context` attribute in user archive export ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30653))

## [4.2.9] - 2024-05-30

### Security
Expand Down
1 change: 1 addition & 0 deletions app/controllers/api/v1/scheduled_statuses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ class Api::V1::ScheduledStatusesController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, except: [:update, :destroy]
before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:update, :destroy]

before_action :require_user!
before_action :set_statuses, only: :index
before_action :set_status, except: :index

Expand Down
1 change: 1 addition & 0 deletions app/controllers/api/v1/statuses/translations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class Api::V1::Statuses::TranslationsController < Api::BaseController
include Authorization

before_action -> { doorkeeper_authorize! :read, :'read:statuses' }
before_action :require_user!
before_action :set_status
before_action :set_translation

Expand Down
1 change: 1 addition & 0 deletions app/controllers/api/v1/timelines/public_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

class Api::V1::Timelines::PublicController < Api::BaseController
before_action -> { authorize_if_got_token! :read, :'read:statuses' }
before_action :require_user!, only: [:show], if: :require_auth?
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }

Expand Down
3 changes: 2 additions & 1 deletion app/controllers/api/v1/timelines/tag_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# frozen_string_literal: true

class Api::V1::Timelines::TagController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: :show, if: :require_auth?
before_action -> { authorize_if_got_token! :read, :'read:statuses' }
before_action :require_user!, if: :require_auth?
before_action :load_tag
after_action :insert_pagination_headers, unless: -> { @statuses.empty? }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicatio

def destroy
Web::PushSubscription.unsubscribe_for(params[:id], current_resource_owner)
Doorkeeper::Application.find_by(id: params[:id])&.close_streaming_sessions(current_resource_owner)
super
end

Expand Down
2 changes: 1 addition & 1 deletion app/lib/activitypub/activity/create.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def distribute
def find_existing_status
status = status_from_uri(object_uri)
status ||= Status.find_by(uri: @object['atomUri']) if @object['atomUri'].present?
status
status if status&.account_id == @account.id
end

def process_status_params
Expand Down
8 changes: 5 additions & 3 deletions app/lib/application_extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,19 @@ module ApplicationExtension
# dependent: delete_all, which means the ActiveRecord callback in
# AccessTokenExtension is not run, so instead we manually announce to
# streaming that these tokens are being deleted.
before_destroy :push_to_streaming_api, prepend: true
before_destroy :close_streaming_sessions, prepend: true
end

def confirmation_redirect_uri
redirect_uri.lines.first.strip
end

def push_to_streaming_api
def close_streaming_sessions(resource_owner = nil)
# TODO: #28793 Combine into a single topic
payload = Oj.dump(event: :kill)
access_tokens.in_batches do |tokens|
scope = access_tokens
scope = scope.where(resource_owner_id: resource_owner.id) unless resource_owner.nil?
scope.in_batches do |tokens|
redis.pipelined do |pipeline|
tokens.ids.each do |id|
pipeline.publish("timeline:access_token:#{id}", payload)
Expand Down
6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ services:

web:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.9
image: ghcr.io/mastodon/mastodon:v4.2.10
restart: always
env_file: .env.production
command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000"
Expand All @@ -77,7 +77,7 @@ services:

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

sidekiq:
build: .
image: ghcr.io/mastodon/mastodon:v4.2.9
image: ghcr.io/mastodon/mastodon:v4.2.10
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
9
10
end

def default_prerelease
Expand Down
11 changes: 11 additions & 0 deletions spec/controllers/api/v1/scheduled_statuses_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@
allow(controller).to receive(:doorkeeper_token) { token }
end

context 'with an application token' do
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read:statuses') }

it 'returns http unprocessable entity' do
get :index

expect(response)
.to have_http_status(422)
end
end

describe 'GET #index' do
it 'returns http success' do
get :index
Expand Down
20 changes: 20 additions & 0 deletions spec/controllers/api/v1/statuses/translations_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,26 @@
let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses', application: app) }

context 'with an application token' do
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: 'read:statuses', application: app) }

before do
allow(controller).to receive(:doorkeeper_token) { token }
end

describe 'POST /api/v1/statuses/:status_id/translate' do
let(:status) { Fabricate(:status, account: user.account, text: 'Hola', language: 'es') }

before do
post :create, params: { status_id: status.id }
end

it 'returns http unprocessable entity' do
expect(response).to have_http_status(422)
end
end
end

context 'with an oauth token' do
before do
allow(controller).to receive(:doorkeeper_token) { token }
Expand Down
19 changes: 15 additions & 4 deletions spec/controllers/api/v1/timelines/tag_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
render_views

let(:user) { Fabricate(:user) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') }
let(:scopes) { 'read:statuses' }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }

before do
allow(controller).to receive(:doorkeeper_token) { token }
Expand Down Expand Up @@ -48,13 +49,23 @@
Form::AdminSettings.new(timeline_preview: false).save
end

context 'when the user is not authenticated' do
context 'without an access token' do
let(:token) { nil }

it 'returns http unauthorized' do
it 'returns http unprocessable entity' do
subject

expect(response).to have_http_status(422)
end
end

context 'with an application access token, not bound to a user' do
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: scopes) }

it 'returns http unprocessable entity' do
subject

expect(response).to have_http_status(401)
expect(response).to have_http_status(422)
end
end

Expand Down
10 changes: 10 additions & 0 deletions spec/controllers/oauth/authorized_applications_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@
let!(:application) { Fabricate(:application) }
let!(:access_token) { Fabricate(:accessible_access_token, application: application, resource_owner_id: user.id) }
let!(:web_push_subscription) { Fabricate(:web_push_subscription, user: user, access_token: access_token) }
let(:redis_pipeline_stub) { instance_double(Redis::Namespace, publish: nil) }

before do
sign_in user, scope: :user
allow(redis).to receive(:pipelined).and_yield(redis_pipeline_stub)
post :destroy, params: { id: application.id }
end

Expand All @@ -63,5 +65,13 @@
it 'removes subscriptions for the application\'s access tokens' do
expect(Web::PushSubscription.where(user: user).count).to eq 0
end

it 'removes the web_push_subscription' do
expect { web_push_subscription.reload }.to raise_error(ActiveRecord::RecordNotFound)
end

it 'sends a session kill payload to the streaming server' do
expect(redis_pipeline_stub).to have_received(:publish).with("timeline:access_token:#{access_token.id}", '{"event":"kill"}')
end
end
end
8 changes: 8 additions & 0 deletions spec/controllers/settings/applications_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ def call_update
end

describe 'destroy' do
let(:redis_pipeline_stub) { instance_double(Redis::Namespace, publish: nil) }
let!(:access_token) { Fabricate(:accessible_access_token, application: app) }

before do
allow(redis).to receive(:pipelined).and_yield(redis_pipeline_stub)
post :destroy, params: { id: app.id }
end

Expand All @@ -177,6 +181,10 @@ def call_update
it 'removes the app' do
expect(Doorkeeper::Application.find_by(id: app.id)).to be_nil
end

it 'sends a session kill payload to the streaming server' do
expect(redis_pipeline_stub).to have_received(:publish).with("timeline:access_token:#{access_token.id}", '{"event":"kill"}')
end
end

describe 'regenerate' do
Expand Down
24 changes: 19 additions & 5 deletions spec/requests/api/v1/timelines/public_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
context 'when the instance allows public preview' do
let(:expected_statuses) { [local_status, remote_status, media_status] }

it_behaves_like 'forbidden for wrong scope', 'profile'

context 'with an authorized user' do
it_behaves_like 'a successful request to the public timeline'
end
Expand Down Expand Up @@ -96,21 +98,33 @@
Form::AdminSettings.new(timeline_preview: false).save
end

context 'with an authenticated user' do
let(:expected_statuses) { [local_status, remote_status, media_status] }
it_behaves_like 'forbidden for wrong scope', 'profile'

it_behaves_like 'a successful request to the public timeline'
context 'without an authentication token' do
let(:headers) { {} }

it 'returns http unprocessable entity' do
subject

expect(response).to have_http_status(422)
end
end

context 'with an unauthenticated user' do
let(:headers) { {} }
context 'with an application access token, not bound to a user' do
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: nil, scopes: scopes) }

it 'returns http unprocessable entity' do
subject

expect(response).to have_http_status(422)
end
end

context 'with an authenticated user' do
let(:expected_statuses) { [local_status, remote_status, media_status] }

it_behaves_like 'a successful request to the public timeline'
end
end
end
end

0 comments on commit 441dca1

Please sign in to comment.