From 4a9abd93ab7e75752a704305333fb33f678df3ce Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 16 Jan 2025 11:10:08 +0100 Subject: [PATCH 1/5] Merge commit from fork --- app/lib/delivery_failure_tracker.rb | 2 ++ .../activitypub/process_account_service.rb | 27 ++++++++++++++----- spec/lib/delivery_failure_tracker_spec.rb | 4 +-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/app/lib/delivery_failure_tracker.rb b/app/lib/delivery_failure_tracker.rb index c90716632..dce27d9af 100644 --- a/app/lib/delivery_failure_tracker.rb +++ b/app/lib/delivery_failure_tracker.rb @@ -46,6 +46,8 @@ class DeliveryFailureTracker urls.reject do |url| host = Addressable::URI.parse(url).normalized_host unavailable_domains_map[host] + rescue Addressable::URI::InvalidURIError, IDN::Idna::IdnaError + true end end diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 5edf52325..871042466 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -9,6 +9,8 @@ class ActivityPub::ProcessAccountService < BaseService SUBDOMAINS_RATELIMIT = 10 DISCOVERIES_PER_REQUEST = 400 + VALID_URI_SCHEMES = %w(http https).freeze + # Should be called with confirmed valid JSON # and WebFinger-resolved username and domain def call(username, domain, json, options = {}) @@ -96,16 +98,28 @@ class ActivityPub::ProcessAccountService < BaseService end def set_immediate_protocol_attributes! - @account.inbox_url = @json['inbox'] || '' - @account.outbox_url = @json['outbox'] || '' - @account.shared_inbox_url = (@json['endpoints'].is_a?(Hash) ? @json['endpoints']['sharedInbox'] : @json['sharedInbox']) || '' - @account.followers_url = @json['followers'] || '' + @account.inbox_url = valid_collection_uri(@json['inbox']) + @account.outbox_url = valid_collection_uri(@json['outbox']) + @account.shared_inbox_url = valid_collection_uri(@json['endpoints'].is_a?(Hash) ? @json['endpoints']['sharedInbox'] : @json['sharedInbox']) + @account.followers_url = valid_collection_uri(@json['followers']) @account.url = url || @uri @account.uri = @uri @account.actor_type = actor_type @account.created_at = @json['published'] if @json['published'].present? end + def valid_collection_uri(uri) + uri = uri.first if uri.is_a?(Array) + uri = uri['id'] if uri.is_a?(Hash) + return '' unless uri.is_a?(String) + + parsed_uri = Addressable::URI.parse(uri) + + VALID_URI_SCHEMES.include?(parsed_uri.scheme) && parsed_uri.host.present? ? parsed_uri : '' + rescue Addressable::URI::InvalidURIError + '' + end + def set_immediate_attributes! @account.featured_collection_url = @json['featured'] || '' @account.devices_url = @json['devices'] || '' @@ -268,10 +282,11 @@ class ActivityPub::ProcessAccountService < BaseService end def collection_info(type) - return [nil, nil] if @json[type].blank? + collection_uri = valid_collection_uri(@json[type]) + return [nil, nil] if collection_uri.blank? return @collections[type] if @collections.key?(type) - collection = fetch_resource_without_id_validation(@json[type]) + collection = fetch_resource_without_id_validation(collection_uri) total_items = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil has_first_page = collection.is_a?(Hash) && collection['first'].present? diff --git a/spec/lib/delivery_failure_tracker_spec.rb b/spec/lib/delivery_failure_tracker_spec.rb index c8179ebd9..a6328f573 100644 --- a/spec/lib/delivery_failure_tracker_spec.rb +++ b/spec/lib/delivery_failure_tracker_spec.rb @@ -42,8 +42,8 @@ describe DeliveryFailureTracker do Fabricate(:unavailable_domain, domain: 'foo.bar') end - it 'removes URLs that are unavailable' do - results = described_class.without_unavailable(['http://example.com/good/inbox', 'http://foo.bar/unavailable/inbox']) + it 'removes URLs that are bogus or unavailable' do + results = described_class.without_unavailable(['http://example.com/good/inbox', 'http://foo.bar/unavailable/inbox', '{foo:']) expect(results).to include('http://example.com/good/inbox') expect(results).to_not include('http://foo.bar/unavailable/inbox') From e6b97fc9404e293778f78fdba552109d246ef2cf Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 15 Jan 2025 12:50:50 +0100 Subject: [PATCH 2/5] Fix deletion of unconfirmed users with Webauthn set (#33186) --- .../scheduler/user_cleanup_scheduler.rb | 1 + .../scheduler/user_cleanup_scheduler_spec.rb | 21 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/workers/scheduler/user_cleanup_scheduler.rb b/app/workers/scheduler/user_cleanup_scheduler.rb index 2d2efc731..3537c99dc 100644 --- a/app/workers/scheduler/user_cleanup_scheduler.rb +++ b/app/workers/scheduler/user_cleanup_scheduler.rb @@ -16,6 +16,7 @@ class Scheduler::UserCleanupScheduler User.where('confirmed_at is NULL AND confirmation_sent_at <= ?', 2.days.ago).reorder(nil).find_in_batches do |batch| # We have to do it separately because of missing database constraints AccountModerationNote.where(target_account_id: batch.map(&:account_id)).delete_all + WebauthnCredential.where(user_id: batch.map(&:id)).delete_all Account.where(id: batch.map(&:account_id)).delete_all User.where(id: batch.map(&:id)).delete_all end diff --git a/spec/workers/scheduler/user_cleanup_scheduler_spec.rb b/spec/workers/scheduler/user_cleanup_scheduler_spec.rb index 990979500..649ed11de 100644 --- a/spec/workers/scheduler/user_cleanup_scheduler_spec.rb +++ b/spec/workers/scheduler/user_cleanup_scheduler_spec.rb @@ -9,6 +9,7 @@ describe Scheduler::UserCleanupScheduler do let!(:old_unconfirmed_user) { Fabricate(:user) } let!(:confirmed_user) { Fabricate(:user) } let!(:moderation_note) { Fabricate(:account_moderation_note, account: Fabricate(:account), target_account: old_unconfirmed_user.account) } + let!(:webauthn_credential) { Fabricate(:webauthn_credential, user_id: old_unconfirmed_user.id) } describe '#perform' do before do @@ -18,8 +19,24 @@ describe Scheduler::UserCleanupScheduler do confirmed_user.update!(confirmed_at: 1.day.ago) end - it 'deletes the old unconfirmed user' do - expect { subject.perform }.to change { User.exists?(old_unconfirmed_user.id) }.from(true).to(false) + it 'deletes the old unconfirmed user and metadata while preserving confirmed user and newer unconfirmed user' do + expect { subject.perform } + .to change { User.exists?(old_unconfirmed_user.id) } + .from(true).to(false) + .and change { Account.exists?(old_unconfirmed_user.account_id) } + .from(true).to(false) + expect { moderation_note.reload } + .to raise_error(ActiveRecord::RecordNotFound) + expect { webauthn_credential.reload } + .to raise_error(ActiveRecord::RecordNotFound) + expect(User.exists?(new_unconfirmed_user.id)) + .to be true + expect(User.exists?(confirmed_user.id)) + .to be true + expect(Account.exists?(new_unconfirmed_user.account_id)) + .to be true + expect(Account.exists?(confirmed_user.account_id)) + .to be true end it "deletes the old unconfirmed user's account" do From e86430a45bd4eee2b88f268c23da63337747bb81 Mon Sep 17 00:00:00 2001 From: Michael Stanclift Date: Tue, 14 Jan 2025 10:35:58 -0600 Subject: [PATCH 3/5] Fix libyaml missing from Dockerfile build stage (#33591) --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 980d70509..c9bc33b31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,6 +28,7 @@ RUN apt-get update && \ libgdbm-dev \ libgmp-dev \ libssl-dev \ + libyaml-dev \ libyaml-0-2 \ ca-certificates \ libreadline8 \ From c953fe9754eb60ccbb5de2aec9c7459bb2d634d5 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 15 Jan 2025 13:11:10 +0100 Subject: [PATCH 4/5] Update dependencies rails and rails-html-sanitizer --- Gemfile.lock | 117 ++++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5c3cf1c56..2008d6390 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -28,47 +28,47 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (7.0.8.6) - actionpack (= 7.0.8.6) - activesupport (= 7.0.8.6) + actioncable (7.0.8.7) + actionpack (= 7.0.8.7) + activesupport (= 7.0.8.7) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.8.6) - actionpack (= 7.0.8.6) - activejob (= 7.0.8.6) - activerecord (= 7.0.8.6) - activestorage (= 7.0.8.6) - activesupport (= 7.0.8.6) + actionmailbox (7.0.8.7) + actionpack (= 7.0.8.7) + activejob (= 7.0.8.7) + activerecord (= 7.0.8.7) + activestorage (= 7.0.8.7) + activesupport (= 7.0.8.7) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.8.6) - actionpack (= 7.0.8.6) - actionview (= 7.0.8.6) - activejob (= 7.0.8.6) - activesupport (= 7.0.8.6) + actionmailer (7.0.8.7) + actionpack (= 7.0.8.7) + actionview (= 7.0.8.7) + activejob (= 7.0.8.7) + activesupport (= 7.0.8.7) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.0) - actionpack (7.0.8.6) - actionview (= 7.0.8.6) - activesupport (= 7.0.8.6) + actionpack (7.0.8.7) + actionview (= 7.0.8.7) + activesupport (= 7.0.8.7) rack (~> 2.0, >= 2.2.4) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.8.6) - actionpack (= 7.0.8.6) - activerecord (= 7.0.8.6) - activestorage (= 7.0.8.6) - activesupport (= 7.0.8.6) + actiontext (7.0.8.7) + actionpack (= 7.0.8.7) + activerecord (= 7.0.8.7) + activestorage (= 7.0.8.7) + activesupport (= 7.0.8.7) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.8.6) - activesupport (= 7.0.8.6) + actionview (7.0.8.7) + activesupport (= 7.0.8.7) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -78,22 +78,22 @@ GEM activemodel (>= 4.1, < 7.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.0.8.6) - activesupport (= 7.0.8.6) + activejob (7.0.8.7) + activesupport (= 7.0.8.7) globalid (>= 0.3.6) - activemodel (7.0.8.6) - activesupport (= 7.0.8.6) - activerecord (7.0.8.6) - activemodel (= 7.0.8.6) - activesupport (= 7.0.8.6) - activestorage (7.0.8.6) - actionpack (= 7.0.8.6) - activejob (= 7.0.8.6) - activerecord (= 7.0.8.6) - activesupport (= 7.0.8.6) + activemodel (7.0.8.7) + activesupport (= 7.0.8.7) + activerecord (7.0.8.7) + activemodel (= 7.0.8.7) + activesupport (= 7.0.8.7) + activestorage (7.0.8.7) + actionpack (= 7.0.8.7) + activejob (= 7.0.8.7) + activerecord (= 7.0.8.7) + activesupport (= 7.0.8.7) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (7.0.8.6) + activesupport (7.0.8.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -469,7 +469,7 @@ GEM net-protocol net-ssh (7.1.0) nio4r (2.7.4) - nokogiri (1.16.7) + nokogiri (1.16.8) mini_portile2 (~> 2.8.2) racc (~> 1.4) nsa (0.3.0) @@ -550,20 +550,20 @@ GEM rack rack-test (2.1.0) rack (>= 1.3) - rails (7.0.8.6) - actioncable (= 7.0.8.6) - actionmailbox (= 7.0.8.6) - actionmailer (= 7.0.8.6) - actionpack (= 7.0.8.6) - actiontext (= 7.0.8.6) - actionview (= 7.0.8.6) - activejob (= 7.0.8.6) - activemodel (= 7.0.8.6) - activerecord (= 7.0.8.6) - activestorage (= 7.0.8.6) - activesupport (= 7.0.8.6) + rails (7.0.8.7) + actioncable (= 7.0.8.7) + actionmailbox (= 7.0.8.7) + actionmailer (= 7.0.8.7) + actionpack (= 7.0.8.7) + actiontext (= 7.0.8.7) + actionview (= 7.0.8.7) + activejob (= 7.0.8.7) + activemodel (= 7.0.8.7) + activerecord (= 7.0.8.7) + activestorage (= 7.0.8.7) + activesupport (= 7.0.8.7) bundler (>= 1.15.0) - railties (= 7.0.8.6) + railties (= 7.0.8.7) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -572,15 +572,15 @@ GEM activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.2) loofah (~> 2.21) - nokogiri (~> 1.14) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) rails-i18n (7.0.7) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) - railties (7.0.8.6) - actionpack (= 7.0.8.6) - activesupport (= 7.0.8.6) + railties (7.0.8.7) + actionpack (= 7.0.8.7) + activesupport (= 7.0.8.7) method_source rake (>= 12.2) thor (~> 1.0) @@ -743,7 +743,7 @@ GEM test-prof (1.2.3) thor (1.3.2) tilt (2.2.0) - timeout (0.4.2) + timeout (0.4.3) tpm-key_attestation (0.12.0) bindata (~> 2.4) openssl (> 2.0) @@ -800,7 +800,8 @@ GEM railties (>= 5.2) semantic_range (>= 2.3.0) websocket (1.2.9) - websocket-driver (0.7.6) + websocket-driver (0.7.7) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) wisper (2.0.1) From bf4d0f0dcad88d63fc747520a5a1f47255130bf8 Mon Sep 17 00:00:00 2001 From: Claire Date: Wed, 15 Jan 2025 13:28:27 +0100 Subject: [PATCH 5/5] Bump version to v4.2.15 --- CHANGELOG.md | 12 ++++++++++++ docker-compose.yml | 6 +++--- lib/mastodon/version.rb | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a278646e..85a830ad7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. +## [4.2.15] - 2025-01-16 + +### Security + +- Fix insufficient validation of account URIs ([GHSA-5wxh-3p65-r4g6](https://github.com/mastodon/mastodon/security/advisories/GHSA-5wxh-3p65-r4g6)) +- Update dependencies + +### Fixed + +- Fix `libyaml` missing from `Dockerfile` build stage (#33591 by @vmstan) +- Fix deletion of unconfirmed users with Webauthn set (#33186 by @ClearlyClaire) + ## [4.2.14] - 2024-02-03 ### Added diff --git a/docker-compose.yml b/docker-compose.yml index ad71f3725..d6fa5ebfe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -56,7 +56,7 @@ services: web: build: . - image: ghcr.io/mastodon/mastodon:v4.2.14 + image: ghcr.io/mastodon/mastodon:v4.2.15 restart: always env_file: .env.production command: bash -c "rm -f /mastodon/tmp/pids/server.pid; bundle exec rails s -p 3000" @@ -77,7 +77,7 @@ services: streaming: build: . - image: ghcr.io/mastodon/mastodon:v4.2.14 + image: ghcr.io/mastodon/mastodon:v4.2.15 restart: always env_file: .env.production command: node ./streaming @@ -95,7 +95,7 @@ services: sidekiq: build: . - image: ghcr.io/mastodon/mastodon:v4.2.14 + image: ghcr.io/mastodon/mastodon:v4.2.15 restart: always env_file: .env.production command: bundle exec sidekiq diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index d266738d5..9156b6916 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -13,7 +13,7 @@ module Mastodon end def patch - 14 + 15 end def default_prerelease