From 74172ced81784321a025e80db5227ec47d139d58 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 09:20:24 +0200 Subject: [PATCH 1/5] Update dependency playwright to v1.55.1 [SECURITY] (#36534) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index e33939fcd4..acd1bc71bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10410,27 +10410,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.55.0": - version: 1.55.0 - resolution: "playwright-core@npm:1.55.0" +"playwright-core@npm:1.56.1": + version: 1.56.1 + resolution: "playwright-core@npm:1.56.1" bin: playwright-core: cli.js - checksum: 10c0/c39d6aa30e7a4e73965942ca5e13405ae05c9cb49f755a35f04248c864c0b24cf662d9767f1797b3ec48d1cf4e54774dce4a19c16534bd5cfd2aa3da81c9dc3a + checksum: 10c0/ffd40142b99c68678b387445d5b42f1fee4ab0b65d983058c37f342e5629f9cdbdac0506ea80a0dfd41a8f9f13345bad54e9a8c35826ef66dc765f4eb3db8da7 languageName: node linkType: hard "playwright@npm:^1.54.1": - version: 1.55.0 - resolution: "playwright@npm:1.55.0" + version: 1.56.1 + resolution: "playwright@npm:1.56.1" dependencies: fsevents: "npm:2.3.2" - playwright-core: "npm:1.55.0" + playwright-core: "npm:1.56.1" dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 10c0/51605b7e57a5650e57972c5fdfc09d7a9934cca1cbee5beacca716fa801e25cb5bb7c1663de90c22b300fde884e5545a2b13a0505a93270b660687791c478304 + checksum: 10c0/8e9965aede86df0f4722063385748498977b219630a40a10d1b82b8bd8d4d4e9b6b65ecbfa024331a30800163161aca292fb6dd7446c531a1ad25f4155625ab4 languageName: node linkType: hard From 2eccd7b53cfd15ed5d4bbdb1ed4abfa6eac8d1b8 Mon Sep 17 00:00:00 2001 From: Matt Jankowski Date: Tue, 21 Oct 2025 03:33:30 -0400 Subject: [PATCH 2/5] Specs for validation error in API responses (#36507) --- spec/requests/api/v1/accounts/credentials_spec.rb | 5 +++++ spec/requests/api/v1/accounts_spec.rb | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/spec/requests/api/v1/accounts/credentials_spec.rb b/spec/requests/api/v1/accounts/credentials_spec.rb index 84bea97e80..4316c1409d 100644 --- a/spec/requests/api/v1/accounts/credentials_spec.rb +++ b/spec/requests/api/v1/accounts/credentials_spec.rb @@ -91,6 +91,11 @@ RSpec.describe 'credentials API' do expect(response).to have_http_status(422) expect(response.content_type) .to start_with('application/json') + expect(response.parsed_body) + .to include( + error: /Validation failed/, + details: include(note: contain_exactly(include(error: 'ERR_TOO_LONG', description: /character limit/))) + ) end end diff --git a/spec/requests/api/v1/accounts_spec.rb b/spec/requests/api/v1/accounts_spec.rb index 0e64915baf..9bbce4877e 100644 --- a/spec/requests/api/v1/accounts_spec.rb +++ b/spec/requests/api/v1/accounts_spec.rb @@ -118,6 +118,11 @@ RSpec.describe '/api/v1/accounts' do .to have_http_status(422) expect(response.content_type) .to start_with('application/json') + expect(response.parsed_body) + .to include( + error: /Validation failed/, + details: include(date_of_birth: contain_exactly(include(error: 'ERR_BELOW_LIMIT', description: /below the age limit/))) + ) end end From 2b9e4294fe9da937a0c063dc2f1fcace2eac3caf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 10:50:24 +0200 Subject: [PATCH 3/5] New Crowdin Translations (automated) (#36538) Co-authored-by: GitHub Actions --- config/locales/simple_form.be.yml | 2 ++ config/locales/simple_form.nn.yml | 2 ++ config/locales/simple_form.tr.yml | 2 ++ config/locales/tr.yml | 1 + 4 files changed, 7 insertions(+) diff --git a/config/locales/simple_form.be.yml b/config/locales/simple_form.be.yml index 9ee1b3873c..cee48c7ded 100644 --- a/config/locales/simple_form.be.yml +++ b/config/locales/simple_form.be.yml @@ -65,6 +65,7 @@ be: setting_display_media_hide_all: Заўсёды хаваць медыя setting_display_media_show_all: Заўсёды паказваць медыя setting_emoji_style: Як паказваць эмодзі. "Аўтаматычны" будзе намагацца выкарыстоўваць мясцовыя эмодзі, але для састарэлых браўзераў — Twemoji. + setting_quick_boosting_html: Калі ўключана, клік па %{boost_icon} іконцы пашырэння адразу пашырыць допіс, без адкрыцця меню "пашырыць/цытаваць". Перасоўвае дзеянне цытавання ў меню %{options_icon} (выбару). setting_system_scrollbars_ui: Працуе толькі ў камп'ютарных браўзерах на аснове Safari і Chrome setting_use_blurhash: Градыенты заснаваны на колерах схаваных выяў, але размываюць дэталі setting_use_pending_items: Схаваць абнаўленні стужкі за клікам замест аўтаматычнага пракручвання стужкі @@ -254,6 +255,7 @@ be: setting_expand_spoilers: Заўжды разгортваць допісы з папярэджаннем аб змесціве setting_hide_network: Схаваць вашы сувязі setting_missing_alt_text_modal: Папярэджваць перад публікацыяй допісу без альтэрнатыўнага тэксту + setting_quick_boosting: Уключыць хуткае пашырэнне setting_reduce_motion: Памяншэнне руху ў анімацыях setting_system_font_ui: Выкарыстоўваць прадвызначаны сістэмны шрыфт setting_system_scrollbars_ui: Паказваць паласу пракручвання па змаўчанні diff --git a/config/locales/simple_form.nn.yml b/config/locales/simple_form.nn.yml index 889f59dbed..a536fdf99b 100644 --- a/config/locales/simple_form.nn.yml +++ b/config/locales/simple_form.nn.yml @@ -65,6 +65,7 @@ nn: setting_display_media_hide_all: Alltid skjul alt media setting_display_media_show_all: Vis alltid media setting_emoji_style: Korleis du skal visa smilefjes. «Auto» prøver å visa innebygde smilefjes, men bruker Twemoji som reserveløysing for eldre nettlesarar. + setting_quick_boosting_html: Når dette er skrudd på og du klikkar på %{boost_icon} framhev-ikonet, vil du framheva innlegget med ein gong i staden for å opna framhev/siter-menyen. Du finn siteringa i %{options_icon} (Val)-menyen. setting_system_scrollbars_ui: Gjeld berre skrivebordsnettlesarar som er bygde på Safari og Chrome setting_use_blurhash: Overgangar er basert på fargane til skjulte grafikkelement, men gjer detaljar utydelege setting_use_pending_items: Gøym tidslineoppdateringar bak eit klikk, i staden for å rulla ned automatisk @@ -252,6 +253,7 @@ nn: setting_expand_spoilers: Vid alltid ut tut som er merka med innhaldsåtvaringar setting_hide_network: Gøym nettverket ditt setting_missing_alt_text_modal: Åtvar meg før eg legg ut media utan alternativ tekst + setting_quick_boosting: Skru på rask framheving setting_reduce_motion: Minsk rørsle i animasjonar setting_system_font_ui: Bruk standardskrifttypen på systemet setting_system_scrollbars_ui: Bruk standardrullefeltet til systemet diff --git a/config/locales/simple_form.tr.yml b/config/locales/simple_form.tr.yml index 34618a3193..6809bb3f50 100644 --- a/config/locales/simple_form.tr.yml +++ b/config/locales/simple_form.tr.yml @@ -65,6 +65,7 @@ tr: setting_display_media_hide_all: Medyayı her zaman gizle setting_display_media_show_all: Medyayı her zaman göster setting_emoji_style: Emojiler nasıl görüntülensin. "Otomatik" seçeneği yerel emojileri kullanmaya çalışır, ancak eski tarayıcılar için Twemoji'yi kullanır. + setting_quick_boosting_html: Etkinleştirildiğinde, %{boost_icon} Öne Çıkar simgesine tıklandığında, öne çıkar/alıntı açılır menüsünü görüntüleme yerine hemen öne çıkarma işlemi gerçekleştirilir. Alıntı işlevi %{options_icon} (Seçenekler) menüsüne taşınır. setting_system_scrollbars_ui: Yalnızca Safari ve Chrome tabanlı masaüstü tarayıcılar için geçerlidir setting_use_blurhash: Gradyenler gizli görsellerin renklerine dayanır, ancak detayları gizler setting_use_pending_items: Akışı otomatik olarak kaydırmak yerine, zaman çizelgesi güncellemelerini tek bir tıklamayla gizleyin @@ -252,6 +253,7 @@ tr: setting_expand_spoilers: İçerik uyarılarıyla işaretli gönderileri her zaman genişlet setting_hide_network: Sosyal grafiğini gizle setting_missing_alt_text_modal: Alternatif metni olmayan bir medya göndermeden önce beni uyar + setting_quick_boosting: Hızlı öne çıkarmayı etkinleştir setting_reduce_motion: Animasyonlarda hareketi azalt setting_system_font_ui: Sistemin varsayılan yazı tipini kullan setting_system_scrollbars_ui: Sistemin varsayılan kaydırma çubuğunu kullan diff --git a/config/locales/tr.yml b/config/locales/tr.yml index f643891888..8f2894e0c1 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -1191,6 +1191,7 @@ tr: advanced_settings: Gelişmiş ayarlar animations_and_accessibility: Animasyonlar ve erişilebilirlik boosting_preferences: Öne çıkarma seçenekleri + boosting_preferences_info_html: "İpucu: Ayarlardan bağımsız olarak, %{icon} Öne Çıkar simgesine Shift + Tıklama uygulandığından öne çıkarma hemen gerçekleştirilir." discovery: Keşfet localization: body: Mastodon, gönüllüler tarafından çevrilmektedir. From 405a49df44033e7d179f3d44d59fb68a67d54789 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 21 Oct 2025 15:00:28 +0200 Subject: [PATCH 4/5] Merge commit from fork * Refuse granting quote authorization for reblogs * Add validation to reject quotes of reblogs * Do not process quotes of reblogs as potentially valid quotes * Refuse to serve quoted reblogs over REST API --- app/lib/activitypub/activity/quote_request.rb | 2 +- .../status/interaction_policy_concern.rb | 2 +- app/models/quote.rb | 5 ++ app/serializers/rest/base_quote_serializer.rb | 2 +- .../activitypub/verify_quote_service.rb | 4 +- spec/lib/activitypub/activity/create_spec.rb | 54 +++++++++++++++ .../status/interaction_policy_concern_spec.rb | 16 +++++ .../process_status_update_service_spec.rb | 66 +++++++++++++++++++ 8 files changed, 146 insertions(+), 5 deletions(-) diff --git a/app/lib/activitypub/activity/quote_request.rb b/app/lib/activitypub/activity/quote_request.rb index 27dea05bf6..12f48ebb2b 100644 --- a/app/lib/activitypub/activity/quote_request.rb +++ b/app/lib/activitypub/activity/quote_request.rb @@ -7,7 +7,7 @@ class ActivityPub::Activity::QuoteRequest < ActivityPub::Activity return if non_matching_uri_hosts?(@account.uri, @json['id']) quoted_status = status_from_uri(object_uri) - return if quoted_status.nil? || !quoted_status.account.local? || !quoted_status.distributable? + return if quoted_status.nil? || !quoted_status.account.local? || !quoted_status.distributable? || quoted_status.reblog? if StatusPolicy.new(@account, quoted_status).quote? accept_quote_request!(quoted_status) diff --git a/app/models/concerns/status/interaction_policy_concern.rb b/app/models/concerns/status/interaction_policy_concern.rb index dbac017b33..da132a450e 100644 --- a/app/models/concerns/status/interaction_policy_concern.rb +++ b/app/models/concerns/status/interaction_policy_concern.rb @@ -27,7 +27,7 @@ module Status::InteractionPolicyConcern # Returns `:automatic`, `:manual`, `:unknown` or `:denied` def quote_policy_for_account(other_account, preloaded_relations: {}) - return :denied if other_account.nil? || direct_visibility? + return :denied if other_account.nil? || direct_visibility? || reblog? following_author = nil followed_by_author = nil diff --git a/app/models/quote.rb b/app/models/quote.rb index 0d24cb239a..e81d427089 100644 --- a/app/models/quote.rb +++ b/app/models/quote.rb @@ -39,6 +39,7 @@ class Quote < ApplicationRecord validates :activity_uri, presence: true, if: -> { account.local? && quoted_account&.remote? } validates :approval_uri, absence: true, if: -> { quoted_account&.local? } validate :validate_visibility + validate :validate_original_quoted_status after_create_commit :increment_counter_caches! after_destroy_commit :decrement_counter_caches! @@ -85,6 +86,10 @@ class Quote < ApplicationRecord errors.add(:quoted_status_id, :visibility_mismatch) end + def validate_original_quoted_status + errors.add(:quoted_status_id, :reblog_unallowed) if quoted_status&.reblog? + end + def set_activity_uri self.activity_uri = [ActivityPub::TagManager.instance.uri_for(account), '/quote_requests/', SecureRandom.uuid].join end diff --git a/app/serializers/rest/base_quote_serializer.rb b/app/serializers/rest/base_quote_serializer.rb index be9d5cbe6f..2637014b69 100644 --- a/app/serializers/rest/base_quote_serializer.rb +++ b/app/serializers/rest/base_quote_serializer.rb @@ -14,7 +14,7 @@ class REST::BaseQuoteSerializer < ActiveModel::Serializer end def quoted_status - object.quoted_status if object.accepted? && object.quoted_status.present? && !status_filter.filtered_for_quote? + object.quoted_status if object.accepted? && object.quoted_status.present? && !object.quoted_status&.reblog? && !status_filter.filtered_for_quote? end private diff --git a/app/services/activitypub/verify_quote_service.rb b/app/services/activitypub/verify_quote_service.rb index 2badadd425..4dcf11cdfd 100644 --- a/app/services/activitypub/verify_quote_service.rb +++ b/app/services/activitypub/verify_quote_service.rb @@ -73,7 +73,7 @@ class ActivityPub::VerifyQuoteService < BaseService status ||= ActivityPub::FetchRemoteStatusService.new.call(uri, on_behalf_of: @quote.account.followers.local.first, prefetched_body:, request_id: @request_id, depth: @depth + 1) - @quote.update(quoted_status: status) if status.present? + @quote.update(quoted_status: status) if status.present? && !status.reblog? rescue Mastodon::RecursionLimitExceededError, Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS => e @fetching_error = e end @@ -91,7 +91,7 @@ class ActivityPub::VerifyQuoteService < BaseService status = ActivityPub::FetchRemoteStatusService.new.call(object['id'], prefetched_body: object, on_behalf_of: @quote.account.followers.local.first, request_id: @request_id, depth: @depth) - if status.present? + if status.present? && !status.reblog? @quote.update(quoted_status: status) true else diff --git a/spec/lib/activitypub/activity/create_spec.rb b/spec/lib/activitypub/activity/create_spec.rb index 2f2f91e369..1e8a2a29db 100644 --- a/spec/lib/activitypub/activity/create_spec.rb +++ b/spec/lib/activitypub/activity/create_spec.rb @@ -1046,6 +1046,60 @@ RSpec.describe ActivityPub::Activity::Create do end end + context 'with a quote of a known reblog that is otherwise valid' do + let(:quoted_account) { Fabricate(:account, domain: 'quoted.example.com') } + let(:quoted_status) { Fabricate(:status, account: quoted_account, reblog: Fabricate(:status)) } + let(:approval_uri) { 'https://quoted.example.com/quote-approval' } + + let(:object_json) do + build_object( + type: 'Note', + content: 'woah what she said is amazing', + quote: ActivityPub::TagManager.instance.uri_for(quoted_status), + quoteAuthorization: approval_uri + ) + end + + before do + stub_request(:get, approval_uri).to_return(headers: { 'Content-Type': 'application/activity+json' }, body: Oj.dump({ + '@context': [ + 'https://www.w3.org/ns/activitystreams', + { + QuoteAuthorization: 'https://w3id.org/fep/044f#QuoteAuthorization', + gts: 'https://gotosocial.org/ns#', + interactionPolicy: { + '@id': 'gts:interactionPolicy', + '@type': '@id', + }, + interactingObject: { + '@id': 'gts:interactingObject', + '@type': '@id', + }, + interactionTarget: { + '@id': 'gts:interactionTarget', + '@type': '@id', + }, + }, + ], + type: 'QuoteAuthorization', + id: approval_uri, + attributedTo: ActivityPub::TagManager.instance.uri_for(quoted_status.account), + interactingObject: object_json[:id], + interactionTarget: ActivityPub::TagManager.instance.uri_for(quoted_status), + })) + end + + it 'creates a status without the verified quote' do + expect { subject.perform }.to change(sender.statuses, :count).by(1) + + status = sender.statuses.first + expect(status).to_not be_nil + expect(status.quote).to_not be_nil + expect(status.quote.state).to_not eq 'accepted' + expect(status.quote.quoted_status).to be_nil + end + end + context 'when a vote to a local poll' do let(:poll) { Fabricate(:poll, options: %w(Yellow Blue)) } let!(:local_status) { Fabricate(:status, poll: poll) } diff --git a/spec/models/concerns/status/interaction_policy_concern_spec.rb b/spec/models/concerns/status/interaction_policy_concern_spec.rb index b59a1186d9..ebc261fc76 100644 --- a/spec/models/concerns/status/interaction_policy_concern_spec.rb +++ b/spec/models/concerns/status/interaction_policy_concern_spec.rb @@ -15,6 +15,22 @@ RSpec.describe Status::InteractionPolicyConcern do describe '#quote_policy_for_account' do let(:account) { Fabricate(:account) } + context 'when the account is the author' do + let(:status) { Fabricate(:status, account: account, quote_approval_policy: 0) } + + it 'returns :automatic' do + expect(status.quote_policy_for_account(account)).to eq :automatic + end + + context 'when it is a reblog' do + let(:status) { Fabricate(:status, account: account, quote_approval_policy: 0, reblog: Fabricate(:status)) } + + it 'returns :automatic' do + expect(status.quote_policy_for_account(account)).to eq :denied + end + end + end + context 'when the account is not following the user' do it 'returns :manual because of the public entry in the manual policy' do expect(status.quote_policy_for_account(account)).to eq :manual diff --git a/spec/services/activitypub/process_status_update_service_spec.rb b/spec/services/activitypub/process_status_update_service_spec.rb index 56a8c71cbe..9d63c5f1fe 100644 --- a/spec/services/activitypub/process_status_update_service_spec.rb +++ b/spec/services/activitypub/process_status_update_service_spec.rb @@ -810,6 +810,72 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do end end + context 'when the status adds a verifiable quote of a reblog through an explicit update' do + let(:quoted_account) { Fabricate(:account, domain: 'quoted.example.com') } + let(:quoted_status) { Fabricate(:status, account: quoted_account, reblog: Fabricate(:status)) } + let(:approval_uri) { 'https://quoted.example.com/approvals/1' } + + let(:payload) do + { + '@context': [ + 'https://www.w3.org/ns/activitystreams', + { + '@id': 'https://w3id.org/fep/044f#quote', + '@type': '@id', + }, + { + '@id': 'https://w3id.org/fep/044f#quoteAuthorization', + '@type': '@id', + }, + ], + id: 'foo', + type: 'Note', + summary: 'Show more', + content: 'Hello universe', + updated: '2021-09-08T22:39:25Z', + quote: ActivityPub::TagManager.instance.uri_for(quoted_status), + quoteAuthorization: approval_uri, + } + end + + before do + stub_request(:get, approval_uri).to_return(headers: { 'Content-Type': 'application/activity+json' }, body: Oj.dump({ + '@context': [ + 'https://www.w3.org/ns/activitystreams', + { + QuoteAuthorization: 'https://w3id.org/fep/044f#QuoteAuthorization', + gts: 'https://gotosocial.org/ns#', + interactionPolicy: { + '@id': 'gts:interactionPolicy', + '@type': '@id', + }, + interactingObject: { + '@id': 'gts:interactingObject', + '@type': '@id', + }, + interactionTarget: { + '@id': 'gts:interactionTarget', + '@type': '@id', + }, + }, + ], + type: 'QuoteAuthorization', + id: approval_uri, + attributedTo: ActivityPub::TagManager.instance.uri_for(quoted_status.account), + interactingObject: ActivityPub::TagManager.instance.uri_for(status), + interactionTarget: ActivityPub::TagManager.instance.uri_for(quoted_status), + })) + end + + it 'updates the approval URI but does not verify the quote' do + expect { subject.call(status, json, json) } + .to change(status, :quote).from(nil) + expect(status.quote.approval_uri).to eq approval_uri + expect(status.quote.state).to_not eq 'accepted' + expect(status.quote.quoted_status).to be_nil + end + end + context 'when the status adds a unverifiable quote through an implicit update' do let(:quoted_account) { Fabricate(:account, domain: 'quoted.example.com') } let(:quoted_status) { Fabricate(:status, account: quoted_account) } From 118ff13bd028cfb19370a12edb9307ea96007ad7 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 21 Oct 2025 15:43:38 +0200 Subject: [PATCH 5/5] Bump version to v4.5.0-beta.2 (#36543) --- CHANGELOG.md | 19 +++++++++++++++---- docker-compose.yml | 6 +++--- lib/mastodon/version.rb | 2 +- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bebb2a3b15..f634505428 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,12 @@ All notable changes to this project will be documented in this file. ### Added -- **Add support for allowing and authoring quotes** (#35355, #35578, #35614, #35618, #35624, #35626, #35652, #35629, #35665, #35653, #35670, #35677, #35690, #35697, #35689, #35699, #35700, #35701, #35709, #35714, #35713, #35715, #35725, #35749, #35769, #35780, #35762, #35804, #35808, #35805, #35819, #35824, #35828, #35822, #35835, #35865, #35860, #35832, #35891, #35894, #35895, #35820, #35917, #35924, #35925, #35914, #35930, #35941, #35939, #35948, #35955, #35967, #35990, #35991, #35975, #35971, #36002, #35986, #36031, #36034, #36038, #36054, #36052, #36055, #36065, #36068, #36083, #36087, #36080, #36091, #36090, #36118, #36119, #36128, #36094, #36129, #36138, #36132, #36151, #36158, #36171, #36194, #36220, #36169, #36130, #36249, #36153, #36299, #36291, #36301, #36315, #36317, #36364, #36383, #36381, #36459, #36464, and #36461 by @ChaosExAnima, @ClearlyClaire, @Lycolia, @diondiondion, and @tribela)\ +- **Add support for allowing and authoring quotes** (#35355, #35578, #35614, #35618, #35624, #35626, #35652, #35629, #35665, #35653, #35670, #35677, #35690, #35697, #35689, #35699, #35700, #35701, #35709, #35714, #35713, #35715, #35725, #35749, #35769, #35780, #35762, #35804, #35808, #35805, #35819, #35824, #35828, #35822, #35835, #35865, #35860, #35832, #35891, #35894, #35895, #35820, #35917, #35924, #35925, #35914, #35930, #35941, #35939, #35948, #35955, #35967, #35990, #35991, #35975, #35971, #36002, #35986, #36031, #36034, #36038, #36054, #36052, #36055, #36065, #36068, #36083, #36087, #36080, #36091, #36090, #36118, #36119, #36128, #36094, #36129, #36138, #36132, #36151, #36158, #36171, #36194, #36220, #36169, #36130, #36249, #36153, #36299, #36291, #36301, #36315, #36317, #36364, #36383, #36381, #36459, #36464, #36461, #36516 and #36528 by @ChaosExAnima, @ClearlyClaire, @Lycolia, @diondiondion, and @tribela)\ This includes a revamp of the composer interface.\ See https://blog.joinmastodon.org/2025/09/introducing-quote-posts/ for a user-centric overview of the feature, and https://docs.joinmastodon.org/client/quotes/ for API documentation. -- **Add support for fetching and refreshing replies to the web UI** (#35210, #35496, #35575, #35500, #35577, #35602, #35603, #35654, #36141, #36237, #36172, #36256, #36271, #36334, #36382, and #36239 by @ClearlyClaire, @Gargron, and @diondiondion) +- **Add support for fetching and refreshing replies to the web UI** (#35210, #35496, #35575, #35500, #35577, #35602, #35603, #35654, #36141, #36237, #36172, #36256, #36271, #36334, #36382, #36239, #36484 and #36481 by @ClearlyClaire, @Gargron, and @diondiondion) - **Add ability to block words in usernames** (#35407, #35655, and #35806 by @ClearlyClaire and @Gargron) +- Add support for displaying of quote posts in Moderator UI (#35964 by @ThisIsMissEm) - Add support for displaying link previews for Admin UI (#35958 by @ThisIsMissEm) - Add support for dynamic viewport height (#36272 by @e1berd) - Add support for numeric-based URIs for new local accounts (#32724, #36304, #36316, and #36365 by @ClearlyClaire) @@ -26,18 +27,20 @@ All notable changes to this project will be documented in this file. - Add delivery failure tracking and handling to FASP jobs (#35625, #35628, and #35723 by @oneiros) - Add example of quote post with a preview card to development sample data (#35616 by @ClearlyClaire) - Add second set of blocked text that applies to accounts regardless of account age for spam-blocking (#35563 by @ClearlyClaire) -- Add experimental feature to select custom emoji rendering (#35229, #35282, #35253, #35424, #35473, #35483, #35505, #35568, #35605, #35659, #35664, #35739, #35985, #36051, #36071, #36137, #36165, #36248, #36262, #36275, #36293, #36341, #36342, #36366, #36377, #36378, #36385, #36393, #36397, #36403, #36413, #36410, #36454, and #36402 by @ChaosExAnima and @braddunbar)\ +- Added emoji from Twemoji v16 (#36501 and #36530 by @ChaosExAnima) +- Add experimental feature to select custom emoji rendering (#35229, #35282, #35253, #35424, #35473, #35483, #35505, #35568, #35605, #35659, #35664, #35739, #35985, #36051, #36071, #36137, #36165, #36248, #36262, #36275, #36293, #36341, #36342, #36366, #36377, #36378, #36385, #36393, #36397, #36403, #36413, #36410, #36454, #36402, #36503, #36502 and #36532 by @ChaosExAnima and @braddunbar)\ This also completely reworks the processing and rendering of emojis and server-rendered HTML in statuses and other places. ### Changed - Change confirmation dialogs for follow button actions “unfollow”, “unblock”, and “withdraw request” (#36289 by @diondiondion) - Change “Follow” button labels (#36264 by @diondiondion) +- Change appearance settings to introduce new Advanced settings section (#36496 and #36506 by @diondiondion) - Change display of content warnings in Admin UI (#35935 by @ThisIsMissEm) - Change index on `follows` table to improve performance of some queries (#36374 by @ClearlyClaire) - Change links to accounts in settings and moderation views to link to local view unless account is suspended (#36340 by @diondiondion) - Change redirection for denied registration from web app to sign-in page with error message (#36384 by @ClearlyClaire) -- Change `timeline_preview` setting into four more granular settings (#36338 and #36467 by @ClearlyClaire) +- Change `timeline_preview` setting into four more granular settings (#36338, #36467 and #36497 by @ClearlyClaire) - Change wording and design of interaction dialog to simplify it (#36124 by @diondiondion) - Change dropdown menus to allow disabled items to be focused (#36078 by @diondiondion) - Change modal background colours in light mode (#36069 by @diondiondion) @@ -49,9 +52,11 @@ All notable changes to this project will be documented in this file. - Change auditable accounts to be sorted by username in admin action logs interface (#35272 by @breadtk) - Change order of translation restoration and service credit on post card (#33619 by @colindean) - Change position of ‘add more’ to be inside table toolbar on reports (#35963 by @ThisIsMissEm) +- Change docker-compose.yml sidekiq health check to work for both 4.4 and 4.5 (#36498 by @ClearlyClaire) ### Fixed +- Fix relationship not being fetched to evaluate whether to show a quote post (#36517 by @ClearlyClaire) - Fix rendering of poll options in status history modal (#35633 by @ThisIsMissEm) - Fix “mute” button being displayed to unauthenticated visitors in hashtag dropdown (#36353 by @mkljczk) - Fix overflow handling of `.more-from-author` (#36310 by @edent) @@ -76,6 +81,12 @@ All notable changes to this project will be documented in this file. - Fix glitchy status keyboard navigation (#35455 and #35504 by @diondiondion) - Fix post being submitted when pressing “Enter” in the CW field (#35445 by @diondiondion) +## [4.4.8] - 2025-10-21 + +### Security + +- Fix quote control bypass ([GHSA-8h43-rcqj-wpc6](https://github.com/mastodon/mastodon/security/advisories/GHSA-8h43-rcqj-wpc6)) + ## [4.4.7] - 2025-10-15 ### Fixed diff --git a/docker-compose.yml b/docker-compose.yml index 3cc3b7f488..58d7704e41 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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.7 + image: ghcr.io/mastodon/mastodon:v4.4.8 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.7 + image: ghcr.io/mastodon/mastodon-streaming:v4.4.8 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.7 + image: ghcr.io/mastodon/mastodon:v4.4.8 restart: always env_file: .env.production command: bundle exec sidekiq diff --git a/lib/mastodon/version.rb b/lib/mastodon/version.rb index b8f6436fde..ae88b53517 100644 --- a/lib/mastodon/version.rb +++ b/lib/mastodon/version.rb @@ -17,7 +17,7 @@ module Mastodon end def default_prerelease - 'beta.1' + 'beta.2' end def prerelease