Merge commit from fork

* Fix GHSA-7jvv-fhmg-wpfw

* Fix GHSA-vwhj-3g83-v276

* Bump version to v4.4.21
This commit is contained in:
Claire
2026-07-27 16:02:01 +02:00
committed by GitHub
parent 408b49afac
commit da47a1bd3c
11 changed files with 49 additions and 21 deletions

View File

@@ -2,6 +2,25 @@
All notable changes to this project will be documented in this file.
## [4.4.21] - 2026-07-27
### Security
- Fix incorrect permission enforcement ([GHSA-7jvv-fhmg-wpfw](https://github.com/mastodon/mastodon/security/advisories/GHSA-7jvv-fhmg-wpfw))
- Fix SSRF protection bypass via IPv4-compatible IPv6 addresses ([GHSA-vwhj-3g83-v276](https://github.com/mastodon/mastodon/security/advisories/GHSA-vwhj-3g83-v276))
- Update dependencies
### Fixed
- Fix performance of user-focused queries in admin dashboard (#39929 by @ClearlyClaire)
- Fix Web Push subscription deletion endpoint incorrectly expecting anti-CSRF tokens (#39918 by @ClearlyClaire)
- Fix `ActivityPub::Activity::Create` trying to re-create known statuses when author changes (#39916 by @ClearlyClaire)
- Fix lax relevancy check in inbound activity processing (#39892 by @ClearlyClaire)
- Fix `Account::Merging` concern not supporting Quotes, refactor it (#39884 by @ClearlyClaire)
- Fix suspended accounts not being removed from follow request count in `/api/v1/accounts/verify_credentials` (#39858 by @ClearlyClaire)
- Fix followed tags not being properly cleaned up when an account is deleted (#39824 by @shleeable)
- Fix autofollow option being ignored in invite moderation interface (#39819 by @shleeable)
## [4.4.20] - 2026-06-25
### Security

View File

@@ -17,9 +17,9 @@ class Api::V1::Admin::MeasuresController < Api::BaseController
def set_measures
@measures = Admin::Metrics::Measure.retrieve(
params[:keys],
params[:start_at],
params[:end_at],
params.require(:keys),
params.require(:start_at),
params.require(:end_at),
params
)
end

View File

@@ -4,22 +4,22 @@ class Api::V1::Admin::RetentionController < Api::BaseController
include Authorization
before_action -> { authorize_if_got_token! :'admin:read' }
before_action :set_cohorts
before_action :set_retention
after_action :verify_authorized
def create
authorize :dashboard, :index?
render json: @cohorts, each_serializer: REST::Admin::CohortSerializer
render json: @retention.cohorts, each_serializer: REST::Admin::CohortSerializer
end
private
def set_cohorts
@cohorts = Admin::Metrics::Retention.new(
params[:start_at],
params[:end_at],
def set_retention
@retention = Admin::Metrics::Retention.new(
params.require(:start_at),
params.require(:end_at),
params[:frequency]
).cohorts
)
end
end

View File

@@ -17,6 +17,8 @@ class Admin::Metrics::Dimension::BaseDimension
@limit = limit&.to_i
@params = params
@loaded = false
@start_at = [@start_at, @end_at - 2.years].max if @start_at.present? && @end_at.present?
end
def key

View File

@@ -12,10 +12,12 @@ class Admin::Metrics::Measure::BaseMeasure
alias loaded? loaded
def initialize(start_at, end_at, params)
@start_at = start_at&.to_datetime
@end_at = end_at&.to_datetime
@start_at = start_at.to_datetime
@end_at = end_at.to_datetime
@params = params
@loaded = false
@start_at = [@start_at, @end_at - 2.years].max
end
def cache_key

View File

@@ -16,10 +16,13 @@ class Admin::Metrics::Retention
alias loaded? loaded
def initialize(start_at, end_at, frequency)
@start_at = start_at&.to_date
@end_at = end_at&.to_date
@start_at = start_at.to_date
@end_at = end_at.to_date
@frequency = %w(day month).include?(frequency) ? frequency : 'day'
@loaded = false
@start_at = [@start_at, @end_at - (@frequency == 'day' ? 31.days : 12.months)].max
end
def cache_key

View File

@@ -34,7 +34,7 @@ module PrivateAddressCheck
module_function
def private_address?(address)
address = address.native if address.ipv6? && address.ipv4_mapped?
address = address.native if address.ipv6? && (address.ipv4_mapped? || address.ipv4_compat?)
address.private? || address.loopback? || address.link_local? || CIDR_LIST.any? { |cidr| cidr.include?(address) }
end
end

View File

@@ -59,7 +59,7 @@ services:
web:
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
# build: .
image: ghcr.io/mastodon/mastodon:v4.4.20
image: ghcr.io/mastodon/mastodon:v4.4.21
restart: always
env_file: .env.production
command: bundle exec puma -C config/puma.rb
@@ -83,7 +83,7 @@ services:
# build:
# dockerfile: ./streaming/Dockerfile
# context: .
image: ghcr.io/mastodon/mastodon-streaming:v4.4.20
image: ghcr.io/mastodon/mastodon-streaming:v4.4.21
restart: always
env_file: .env.production
command: node ./streaming/index.js
@@ -102,7 +102,7 @@ services:
sidekiq:
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
# build: .
image: ghcr.io/mastodon/mastodon:v4.4.20
image: ghcr.io/mastodon/mastodon:v4.4.21
restart: always
env_file: .env.production
command: bundle exec sidekiq

View File

@@ -13,7 +13,7 @@ module Mastodon
end
def patch
20
21
end
def default_prerelease

View File

@@ -22,6 +22,8 @@ RSpec.describe 'Admin Measures' do
domain: 'mastodon.social',
include_subdomains: true,
},
start_at: '2026-01-01',
end_at: '2026-07-01',
}
end

View File

@@ -11,7 +11,7 @@ RSpec.describe 'Admin Retention' do
describe 'GET /api/v1/admin/retention' do
context 'when not authorized' do
it 'returns http forbidden' do
post '/api/v1/admin/retention', params: { account_id: account.id, limit: 2 }
post '/api/v1/admin/retention', params: { start_at: '2025-01-04', end_at: '2025-07-05', frequency: 'month' }
expect(response)
.to have_http_status(403)
@@ -24,7 +24,7 @@ RSpec.describe 'Admin Retention' do
let(:scopes) { 'admin:read' }
it 'returns http success and status json' do
post '/api/v1/admin/retention', params: { account_id: account.id, limit: 2 }, headers: headers
post '/api/v1/admin/retention', params: { start_at: '2025-01-04', end_at: '2025-07-05', frequency: 'month' }, headers: headers
expect(response)
.to have_http_status(200)