Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge v4.2.9 #71

Merged
merged 28 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ed8e4ba
Fix reference to non-existent var in CLI maintenance command (#28363)
mjankowski Dec 14, 2023
6536d96
Add fallback redirection when getting a webfinger query `WEB_DOMAIN@W…
ClearlyClaire Jan 4, 2024
f784213
Return domain block digests from admin domain blocks API (#29092)
ThisIsMissEm Feb 6, 2024
7af69f5
Fix admin account created by `mastodon:setup` not being auto-approved…
ClearlyClaire Feb 23, 2024
ab3f985
Normalize idna domain before account unblock domain (#29530)
tribela Mar 11, 2024
0143c9d
Fix results/query in `api/v1/featured_tags/suggestions` (#29597)
mjankowski Mar 22, 2024
86807e4
Improve email address validation (#29838)
ClearlyClaire Apr 5, 2024
c3be5a3
Remove caching in `cache_collection` (#29862)
ClearlyClaire Apr 8, 2024
e69780e
Fixed crash when supplying FFMPEG_BINARY environment variable (#30022)
timothyjrogers Apr 22, 2024
51ef619
Fix Idempotency-Key ignored when scheduling a post (#30084)
ClearlyClaire Apr 26, 2024
56b7d1a
Fix not being able to block a subdomain of an already-blocked domain …
ClearlyClaire May 2, 2024
67b2e62
Fix missing destory audit logs for Domain Allows (#30125)
ThisIsMissEm Apr 30, 2024
8cf7882
Fix off-by-one in `tootctl media` commands (#30306)
ClearlyClaire May 15, 2024
8c72e80
Update dependency rack-cors to 2.0.2
ClearlyClaire May 10, 2024
2865bfa
Update dependency json-jwt to 1.15.3.1
ClearlyClaire May 10, 2024
997b021
Update dependency rotp to 6.3.0
ClearlyClaire May 10, 2024
6fc07ff
Update dependency fastimage to 2.3.1
ClearlyClaire May 10, 2024
a8dd321
Update dependency nokogiri to 1.16.5
ClearlyClaire May 16, 2024
16213a6
Update dependency rexml to 3.2.8
ClearlyClaire May 29, 2024
b8edc95
Fix leaking Elasticsearch connections in Sidekiq processes (#30450)
ClearlyClaire May 29, 2024
f9c41ae
Normalize language code of incoming posts (#30403)
ClearlyClaire May 23, 2024
186f916
Fix: remove broken OAuth Application vacuuming & throttle OAuth Appli…
ThisIsMissEm May 29, 2024
943792c
Merge pull request from GHSA-5fq7-3p3j-9vrf
ClearlyClaire May 30, 2024
7920aa5
Merge pull request from GHSA-q3rg-xx5v-4mxh
ClearlyClaire May 30, 2024
8ab0ca7
Merge pull request from GHSA-c2r5-cfqr-c553
ClearlyClaire May 30, 2024
9740c7e
Fix rate-limiting incorrectly triggering a session cookie on most end…
ClearlyClaire May 30, 2024
c93aaca
Bump version to v4.2.9 (#30470)
ClearlyClaire May 30, 2024
3cb1df4
Merge tag 'v4.2.9' into merge-v4.2.9
toufali May 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,41 @@

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

## [4.2.9] - 2024-05-30

### Security

- Update dependencies
- Fix private mention filtering ([GHSA-5fq7-3p3j-9vrf](https://github.com/mastodon/mastodon/security/advisories/GHSA-5fq7-3p3j-9vrf))
- Fix password change endpoint not being rate-limited ([GHSA-q3rg-xx5v-4mxh](https://github.com/mastodon/mastodon/security/advisories/GHSA-q3rg-xx5v-4mxh))
- Add hardening around rate-limit bypass ([GHSA-c2r5-cfqr-c553](https://github.com/mastodon/mastodon/security/advisories/GHSA-c2r5-cfqr-c553))

### Added

- Add rate-limit on OAuth application registration ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/30316))
- Add fallback redirection when getting a webfinger query `WEB_DOMAIN@WEB_DOMAIN` ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/28592))
- Add `digest` attribute to `Admin::DomainBlock` entity in REST API ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/29092))

### Removed

- Remove superfluous application-level caching in some controllers ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29862))
- Remove aggressive OAuth application vacuuming ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/30316))

### Fixed

- Fix leaking Elasticsearch connections in Sidekiq processes ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30450))
- Fix language of remote posts not being recognized when using unusual casing ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30403))
- Fix off-by-one in `tootctl media` commands ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30306))
- Fix removal of allowed domains (in `LIMITED_FEDERATION_MODE`) not being recorded in the audit log ([ThisIsMissEm](https://github.com/mastodon/mastodon/pull/30125))
- Fix not being able to block a subdomain of an already-blocked domain through the API ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30119))
- Fix `Idempotency-Key` being ignored when scheduling a post ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/30084))
- Fix crash when supplying the `FFMPEG_BINARY` environment variable ([timothyjrogers](https://github.com/mastodon/mastodon/pull/30022))
- Fix improper email address validation ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29838))
- Fix results/query in `api/v1/featured_tags/suggestions` ([mjankowski](https://github.com/mastodon/mastodon/pull/29597))
- Fix unblocking internationalized domain names under certain conditions ([tribela](https://github.com/mastodon/mastodon/pull/29530))
- Fix admin account created by `mastodon:setup` not being auto-approved ([ClearlyClaire](https://github.com/mastodon/mastodon/pull/29379))
- Fix reference to non-existent var in CLI maintenance command ([mjankowski](https://github.com/mastodon/mastodon/pull/28363))

## [4.2.8] - 2024-02-23

### Added
Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,5 @@ gem 'net-http', '~> 0.3.2'
gem 'rubyzip', '~> 2.3'

gem 'hcaptcha', '~> 7.1'

gem 'mail', '~> 2.8'
15 changes: 9 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fast_blank (1.0.1)
fastimage (2.2.7)
fastimage (2.3.1)
ffi (1.15.5)
ffi-compiler (1.0.1)
ffi (>= 1.0.0)
Expand Down Expand Up @@ -368,7 +368,7 @@ GEM
jmespath (1.6.2)
json (2.6.3)
json-canonicalization (1.0.0)
json-jwt (1.15.3)
json-jwt (1.15.3.1)
activesupport (>= 4.2)
aes_key_wrap
bindata
Expand Down Expand Up @@ -469,7 +469,7 @@ GEM
net-protocol
net-ssh (7.1.0)
nio4r (2.7.0)
nokogiri (1.16.2)
nokogiri (1.16.5)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nsa (0.3.0)
Expand Down Expand Up @@ -537,7 +537,7 @@ GEM
rack (2.2.8.1)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
rack-cors (2.0.1)
rack-cors (2.0.2)
rack (>= 2.0.0)
rack-oauth2 (1.21.3)
activesupport
Expand Down Expand Up @@ -605,8 +605,9 @@ GEM
responders (3.1.0)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.6)
rotp (6.2.2)
rexml (3.2.8)
strscan (>= 3.0.9)
rotp (6.3.0)
rouge (4.1.2)
rpam2 (4.0.2)
rqrcode (2.2.0)
Expand Down Expand Up @@ -736,6 +737,7 @@ GEM
redlock (~> 1.0)
strong_migrations (0.8.0)
activerecord (>= 5.2)
strscan (3.0.9)
swd (1.3.0)
activesupport (>= 3)
attr_required (>= 0.0.5)
Expand Down Expand Up @@ -876,6 +878,7 @@ DEPENDENCIES
letter_opener_web (~> 2.0)
link_header (~> 0.0)
lograge (~> 0.12)
mail (~> 2.8)
mario-redis-lock (~> 1.2)
md-paperclip-azure (~> 2.2)
memory_profiler
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/admin/domain_allows_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ def create
def destroy
authorize @domain_allow, :destroy?
UnallowDomainService.new.call(@domain_allow)
log_action :destroy, @domain_allow

redirect_to admin_instances_path, notice: I18n.t('admin.domain_allows.destroyed_msg')
end

Expand Down
9 changes: 7 additions & 2 deletions app/controllers/api/v1/admin/domain_blocks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@ def show
def create
authorize :domain_block, :create?

@domain_block = DomainBlock.new(resource_params)
existing_domain_block = resource_params[:domain].present? ? DomainBlock.rule_for(resource_params[:domain]) : nil
return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if existing_domain_block.present?
return render json: existing_domain_block, serializer: REST::Admin::ExistingDomainBlockErrorSerializer, status: 422 if conflicts_with_existing_block?(@domain_block, existing_domain_block)

@domain_block = DomainBlock.create!(resource_params)
@domain_block.save!
DomainBlockWorker.perform_async(@domain_block.id)
log_action :create, @domain_block
render json: @domain_block, serializer: REST::Admin::DomainBlockSerializer
Expand All @@ -55,6 +56,10 @@ def destroy

private

def conflicts_with_existing_block?(domain_block, existing_domain_block)
existing_domain_block.present? && (existing_domain_block.domain == TagManager.instance.normalize_domain(domain_block.domain) || !domain_block.stricter_than?(existing_domain_block))
end

def set_domain_blocks
@domain_blocks = filtered_domain_blocks.order(id: :desc).to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def index
private

def set_recently_used_tags
@recently_used_tags = Tag.recently_used(current_account).where.not(id: current_account.featured_tags).limit(10)
@recently_used_tags = Tag.recently_used(current_account).where.not(id: featured_tag_ids).limit(10)
end

def featured_tag_ids
current_account.featured_tags.pluck(:tag_id)
end
end
29 changes: 7 additions & 22 deletions app/controllers/concerns/cache_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,34 +198,19 @@ def render_with_cache(**options)
end
end

# TODO: Rename this method, as it does not perform any caching anymore.
def cache_collection(raw, klass)
return raw unless klass.respond_to?(:with_includes)
return raw unless klass.respond_to?(:preload_cacheable_associations)

raw = raw.cache_ids.to_a if raw.is_a?(ActiveRecord::Relation)
return [] if raw.empty?
records = raw.to_a

cached_keys_with_value = begin
Rails.cache.read_multi(*raw).transform_keys(&:id).transform_values { |r| ActiveRecordCoder.load(r) }
rescue ActiveRecordCoder::Error
{} # The serialization format may have changed, let's pretend it's a cache miss.
end

uncached_ids = raw.map(&:id) - cached_keys_with_value.keys

klass.reload_stale_associations!(cached_keys_with_value.values) if klass.respond_to?(:reload_stale_associations!)

unless uncached_ids.empty?
uncached = klass.where(id: uncached_ids).with_includes.index_by(&:id)

uncached.each_value do |item|
Rails.cache.write(item, ActiveRecordCoder.dump(item))
end
end
klass.preload_cacheable_associations(records)

raw.filter_map { |item| cached_keys_with_value[item.id] || uncached[item.id] }
records
end

# TODO: Rename this method, as it does not perform any caching anymore.
def cache_collection_paginated_by_id(raw, klass, limit, options)
cache_collection raw.cache_ids.to_a_paginated_by_id(limit, options), klass
cache_collection raw.to_a_paginated_by_id(limit, options), klass
end
end
2 changes: 1 addition & 1 deletion app/controllers/well_known/webfinger_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def set_account
username = username_from_resource

@account = begin
if username == Rails.configuration.x.local_domain
if username == Rails.configuration.x.local_domain || username == Rails.configuration.x.web_domain
Account.representative
else
Account.find_local!(username)
Expand Down
11 changes: 9 additions & 2 deletions app/lib/activitypub/parser/status_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
class ActivityPub::Parser::StatusParser
include JsonLdHelper

NORMALIZED_LOCALE_NAMES = LanguagesHelper::SUPPORTED_LOCALES.keys.index_by(&:downcase).freeze

# @param [Hash] json
# @param [Hash] magic_values
# @option magic_values [String] :followers_collection
Expand Down Expand Up @@ -86,6 +88,13 @@ def visibility
end

def language
lang = raw_language_code
lang.presence && NORMALIZED_LOCALE_NAMES.fetch(lang.downcase.to_sym, lang)
end

private

def raw_language_code
if content_language_map?
@object['contentMap'].keys.first
elsif name_language_map?
Expand All @@ -95,8 +104,6 @@ def language
end
end

private

def audience_to
as_array(@object['to'] || @json['to']).map { |x| value_or_id(x) }
end
Expand Down
10 changes: 0 additions & 10 deletions app/lib/vacuum/applications_vacuum.rb

This file was deleted.

2 changes: 1 addition & 1 deletion app/lib/video_metadata_extractor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def valid?
private

def ffmpeg_command_output
command = Terrapin::CommandLine.new('ffprobe', '-i :path -print_format :format -show_format -show_streams -show_error -loglevel :loglevel')
command = Terrapin::CommandLine.new(Rails.configuration.x.ffprobe_binary, '-i :path -print_format :format -show_format -show_streams -show_error -loglevel :loglevel')
command.run(path: @path, format: 'json', loglevel: 'fatal')
end

Expand Down
6 changes: 5 additions & 1 deletion app/models/concerns/account_interactions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ def unmute_conversation!(conversation)
end

def unblock_domain!(other_domain)
block = domain_blocks.find_by(domain: other_domain)
block = domain_blocks.find_by(domain: normalized_domain(other_domain))
block&.destroy
end

Expand Down Expand Up @@ -313,4 +313,8 @@ def relations_map(account_ids, domains = nil, **options)
def remove_potential_friendship(other_account)
PotentialFriendshipTracker.remove(id, other_account.id)
end

def normalized_domain(domain)
TagManager.instance.normalize_domain(domain)
end
end
4 changes: 4 additions & 0 deletions app/models/concerns/cacheable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ def with_includes
includes(@cache_associated)
end

def preload_cacheable_associations(records)
ActiveRecord::Associations::Preloader.new(records: records, associations: @cache_associated).call
end

def cache_ids
select(:id, :updated_at)
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/feed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def from_redis(limit, max_id, since_id, min_id)
unhydrated = redis.zrangebyscore(key, "(#{min_id}", "(#{max_id}", limit: [0, limit], with_scores: true).map(&:first).map(&:to_i)
end

Status.where(id: unhydrated).cache_ids
Status.where(id: unhydrated)
end

def key
Expand Down
2 changes: 1 addition & 1 deletion app/models/public_feed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def get(limit, max_id = nil, since_id = nil, min_id = nil)
scope.merge!(media_only_scope) if media_only?
scope.merge!(language_scope) if account&.chosen_languages.present?

scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
scope.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
end

private
Expand Down
32 changes: 0 additions & 32 deletions app/models/status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -340,38 +340,6 @@ def pins_map(status_ids, account_id)
StatusPin.select('status_id').where(status_id: status_ids).where(account_id: account_id).each_with_object({}) { |p, h| h[p.status_id] = true }
end

def reload_stale_associations!(cached_items)
account_ids = []

cached_items.each do |item|
account_ids << item.account_id
account_ids << item.reblog.account_id if item.reblog?
end

account_ids.uniq!

status_ids = cached_items.map { |item| item.reblog? ? item.reblog_of_id : item.id }.uniq

return if account_ids.empty?

accounts = Account.where(id: account_ids).includes(:account_stat, :user).index_by(&:id)

status_stats = StatusStat.where(status_id: status_ids).index_by(&:status_id)

cached_items.each do |item|
item.account = accounts[item.account_id]
item.reblog.account = accounts[item.reblog.account_id] if item.reblog?

if item.reblog?
status_stat = status_stats[item.reblog.id]
item.reblog.status_stat = status_stat if status_stat.present?
else
status_stat = status_stats[item.id]
item.status_stat = status_stat if status_stat.present?
end
end
end

def from_text(text)
return [] if text.blank?

Expand Down
2 changes: 1 addition & 1 deletion app/models/tag_feed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def get(limit, max_id = nil, since_id = nil, min_id = nil)
scope.merge!(account_filters_scope) if account?
scope.merge!(media_only_scope) if media_only?

scope.cache_ids.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
scope.to_a_paginated_by_id(limit, max_id: max_id, since_id: since_id, min_id: min_id)
end

private
Expand Down
2 changes: 2 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ class User < ApplicationRecord
accepts_nested_attributes_for :invite_request, reject_if: ->(attributes) { attributes['text'].blank? && !Setting.require_invite_text }
validates :invite_request, presence: true, on: :create, if: :invite_text_required?

validates :email, presence: true, email_address: true

validates_with BlacklistedEmailValidator, if: -> { ENV['EMAIL_DOMAIN_LISTS_APPLY_AFTER_CONFIRMATION'] == 'true' || !confirmed? }
validates_with EmailMxValidator, if: :validate_email_dns?
validates :agreement, acceptance: { allow_nil: false, accept: [true, 'true', '1'] }, on: :create
Expand Down
6 changes: 5 additions & 1 deletion app/serializers/rest/admin/domain_block_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# frozen_string_literal: true

class REST::Admin::DomainBlockSerializer < ActiveModel::Serializer
attributes :id, :domain, :created_at, :severity,
attributes :id, :domain, :digest, :created_at, :severity,
:reject_media, :reject_reports,
:private_comment, :public_comment, :obfuscate

def id
object.id.to_s
end

def digest
object.domain_digest
end
end
Loading
Loading